blob: 168097f7a1af9ed09c0eedaf134ad187d5ef1f97 [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 Venturefd2a9382019-09-25 17:47:25 -070029#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070030#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070031#include <phosphor-logging/log.hpp>
32#include <sdbusplus/bus.hpp>
33#include <sdrutils.hpp>
34#include <sensorcommands.hpp>
35#include <sensorutils.hpp>
36#include <storagecommands.hpp>
37#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070038#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070039#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070040
41namespace ipmi
42{
43using ManagedObjectType =
44 std::map<sdbusplus::message::object_path,
45 std::map<std::string, std::map<std::string, DbusVariant>>>;
46
47using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
48
49static constexpr int sensorListUpdatePeriod = 10;
50static constexpr int sensorMapUpdatePeriod = 2;
51
52constexpr size_t maxSDRTotalSize =
53 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
54constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
55
56static uint16_t sdrReservationID;
57static uint32_t sdrLastAdd = noTimestamp;
58static uint32_t sdrLastRemove = noTimestamp;
59
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053060SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070061static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
62
Jason M. Bills17add592018-11-12 14:30:12 -080063// Specify the comparison required to sort and find char* map objects
64struct CmpStr
65{
66 bool operator()(const char *a, const char *b) const
67 {
68 return std::strcmp(a, b) < 0;
69 }
70};
71const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
72 sensorUnits{{{"temperature", SensorUnits::degreesC},
73 {"voltage", SensorUnits::volts},
74 {"current", SensorUnits::amps},
75 {"fan_tach", SensorUnits::rpm},
76 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070077
78void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070079
80static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070081 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070082 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
83 "sensors/'",
84 [](sdbusplus::message::message &m) {
85 sensorTree.clear();
86 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
87 std::chrono::system_clock::now().time_since_epoch())
88 .count();
89 });
90
91static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070092 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070093 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
94 "sensors/'",
95 [](sdbusplus::message::message &m) {
96 sensorTree.clear();
97 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
98 std::chrono::system_clock::now().time_since_epoch())
99 .count();
100 });
101
James Feist392786a2019-03-19 13:36:10 -0700102// this keeps track of deassertions for sensor event status command. A
103// deasertion can only happen if an assertion was seen first.
104static boost::container::flat_map<
105 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
106 thresholdDeassertMap;
107
108static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700109 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700110 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
111 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
112 [](sdbusplus::message::message &m) {
113 boost::container::flat_map<std::string, std::variant<bool, double>>
114 values;
115 m.read(std::string(), values);
116
117 auto findAssert =
118 std::find_if(values.begin(), values.end(), [](const auto &pair) {
119 return pair.first.find("Alarm") != std::string::npos;
120 });
121 if (findAssert != values.end())
122 {
123 auto ptr = std::get_if<bool>(&(findAssert->second));
124 if (ptr == nullptr)
125 {
126 phosphor::logging::log<phosphor::logging::level::ERR>(
127 "thresholdChanged: Assert non bool");
128 return;
129 }
130 if (*ptr)
131 {
132 phosphor::logging::log<phosphor::logging::level::INFO>(
133 "thresholdChanged: Assert",
134 phosphor::logging::entry("SENSOR=%s", m.get_path()));
135 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
136 }
137 else
138 {
139 auto &value =
140 thresholdDeassertMap[m.get_path()][findAssert->first];
141 if (value)
142 {
143 phosphor::logging::log<phosphor::logging::level::INFO>(
144 "thresholdChanged: deassert",
145 phosphor::logging::entry("SENSOR=%s", m.get_path()));
146 value = *ptr;
147 }
148 }
149 }
150 });
151
James Feistaecaef72019-04-26 10:30:32 -0700152static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
153 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700154{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700155 max = 127;
156 min = -128;
157
James Feistaecaef72019-04-26 10:30:32 -0700158 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
159 auto critical =
160 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
161 auto warning =
162 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
163
164 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700165 {
James Feistaecaef72019-04-26 10:30:32 -0700166 auto maxMap = sensorObject->second.find("MaxValue");
167 auto minMap = sensorObject->second.find("MinValue");
168
169 if (maxMap != sensorObject->second.end())
170 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700171 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700172 }
173 if (minMap != sensorObject->second.end())
174 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700175 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700176 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700177 }
James Feistaecaef72019-04-26 10:30:32 -0700178 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700179 {
James Feistaecaef72019-04-26 10:30:32 -0700180 auto lower = critical->second.find("CriticalLow");
181 auto upper = critical->second.find("CriticalHigh");
182 if (lower != critical->second.end())
183 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700184 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700185 min = std::min(value, min);
186 }
187 if (upper != critical->second.end())
188 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700189 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700190 max = std::max(value, max);
191 }
192 }
193 if (warning != sensorMap.end())
194 {
195
196 auto lower = warning->second.find("WarningLow");
197 auto upper = warning->second.find("WarningHigh");
198 if (lower != warning->second.end())
199 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700200 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700201 min = std::min(value, min);
202 }
203 if (upper != warning->second.end())
204 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700205 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700206 max = std::max(value, max);
207 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700208 }
209}
210
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700211static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
212 SensorMap &sensorMap)
213{
214 static boost::container::flat_map<
215 std::string, std::chrono::time_point<std::chrono::steady_clock>>
216 updateTimeMap;
217
218 auto updateFind = updateTimeMap.find(sensorConnection);
219 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
220 if (updateFind != updateTimeMap.end())
221 {
222 lastUpdate = updateFind->second;
223 }
224
225 auto now = std::chrono::steady_clock::now();
226
227 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
228 .count() > sensorMapUpdatePeriod)
229 {
230 updateTimeMap[sensorConnection] = now;
231
Vernon Mauery15419dd2019-05-24 09:40:30 -0700232 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
233 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700234 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
235 "GetManagedObjects");
236
237 ManagedObjectType managedObjects;
238 try
239 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700240 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700241 reply.read(managedObjects);
242 }
243 catch (sdbusplus::exception_t &)
244 {
245 phosphor::logging::log<phosphor::logging::level::ERR>(
246 "Error getting managed objects from connection",
247 phosphor::logging::entry("CONNECTION=%s",
248 sensorConnection.c_str()));
249 return false;
250 }
251
252 SensorCache[sensorConnection] = managedObjects;
253 }
254 auto connection = SensorCache.find(sensorConnection);
255 if (connection == SensorCache.end())
256 {
257 return false;
258 }
259 auto path = connection->second.find(sensorPath);
260 if (path == connection->second.end())
261 {
262 return false;
263 }
264 sensorMap = path->second;
265
266 return true;
267}
268
269/* sensor commands */
270ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
271 ipmi_request_t request,
272 ipmi_response_t response,
273 ipmi_data_len_t dataLen,
274 ipmi_context_t context)
275{
276 *dataLen = 0;
277 printCommand(+netfn, +cmd);
278 return IPMI_CC_INVALID;
279}
280
James Feist7aaf3fe2019-06-25 11:52:11 -0700281namespace meHealth
282{
283constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
284constexpr const char *path = "/xyz/openbmc_project/status/me";
285constexpr const char *interface = "xyz.openbmc_project.SetHealth";
286constexpr const char *method = "SetHealth";
287constexpr const char *critical = "critical";
288constexpr const char *warning = "warning";
289constexpr const char *ok = "ok";
290} // namespace meHealth
291
292static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
293{
294 constexpr const std::array<uint8_t, 10> critical = {
295 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
296 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
297 0x1A};
298
299 std::string state;
300 if (std::find(critical.begin(), critical.end(), eventData2) !=
301 critical.end())
302 {
303 state = meHealth::critical;
304 }
305 // special case 0x3 as we only care about a few states
306 else if (eventData2 == 0x3)
307 {
308 if (eventData3 <= 0x2)
309 {
310 state = meHealth::warning;
311 }
312 else
313 {
314 return;
315 }
316 }
317 else if (std::find(warning.begin(), warning.end(), eventData2) !=
318 warning.end())
319 {
320 state = meHealth::warning;
321 }
322 else
323 {
324 return;
325 }
326 if (disable)
327 {
328 state = meHealth::ok;
329 }
330
331 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
332 auto setHealth =
333 dbus->new_method_call(meHealth::busname, meHealth::path,
334 meHealth::interface, meHealth::method);
335 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
336 try
337 {
338 dbus->call(setHealth);
339 }
340 catch (sdbusplus::exception_t &)
341 {
342 phosphor::logging::log<phosphor::logging::level::ERR>(
343 "Failed to set ME Health");
344 }
345}
346
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700347ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
348{
James Feist7aaf3fe2019-06-25 11:52:11 -0700349 constexpr const uint8_t meId = 0x2C;
350 constexpr const uint8_t meSensorNum = 0x17;
351 constexpr const uint8_t disabled = 0x80;
352
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700353 uint8_t generatorID = 0;
354 uint8_t evmRev = 0;
355 uint8_t sensorType = 0;
356 uint8_t sensorNum = 0;
357 uint8_t eventType = 0;
358 uint8_t eventData1 = 0;
359 std::optional<uint8_t> eventData2 = 0;
360 std::optional<uint8_t> eventData3 = 0;
361
362 // todo: This check is supposed to be based on the incoming channel.
363 // e.g. system channel will provide upto 8 bytes including generator
364 // ID, but ipmb channel will provide only up to 7 bytes without the
365 // generator ID.
366 // Support for this check is coming in future patches, so for now just base
367 // it on if the first byte is the EvMRev (0x04).
368 if (p.size() && p.data()[0] == 0x04)
369 {
370 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
371 eventData2, eventData3);
372 // todo: the generator ID for this channel is supposed to come from the
373 // IPMB requesters slave address. Support for this is coming in future
374 // patches, so for now just assume it is coming from the ME (0x2C).
375 generatorID = 0x2C;
376 }
377 else
378 {
379 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
380 eventData1, eventData2, eventData3);
381 }
382 if (!p.fullyUnpacked())
383 {
384 return ipmi::responseReqDataLenInvalid();
385 }
386
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700387 // Send this request to the Redfish hooks to log it as a Redfish message
388 // instead. There is no need to add it to the SEL, so just return success.
389 intel_oem::ipmi::sel::checkRedfishHooks(
390 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
391 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700392
James Feist7aaf3fe2019-06-25 11:52:11 -0700393 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
394 eventData3)
395 {
396 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
397 }
398
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700399 return ipmi::responseSuccess();
400}
401
James Feist0cd014a2019-04-08 15:04:33 -0700402ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
403 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700404{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700405 std::string connection;
406 std::string path;
407
408 auto status = getSensorConnection(sensnum, connection, path);
409 if (status)
410 {
James Feist0cd014a2019-04-08 15:04:33 -0700411 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700412 }
413
414 SensorMap sensorMap;
415 if (!getSensorMap(connection, path, sensorMap))
416 {
James Feist0cd014a2019-04-08 15:04:33 -0700417 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700418 }
419 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
420
421 if (sensorObject == sensorMap.end() ||
422 sensorObject->second.find("Value") == sensorObject->second.end())
423 {
James Feist0cd014a2019-04-08 15:04:33 -0700424 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700425 }
James Feist0cd014a2019-04-08 15:04:33 -0700426 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700427 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700428
Yong Li1f2eb5e2019-05-23 14:07:17 +0800429 double max = 0;
430 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700431 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700432
433 int16_t mValue = 0;
434 int16_t bValue = 0;
435 int8_t rExp = 0;
436 int8_t bExp = 0;
437 bool bSigned = false;
438
439 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
440 {
James Feist0cd014a2019-04-08 15:04:33 -0700441 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700442 }
443
James Feist0cd014a2019-04-08 15:04:33 -0700444 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700445 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700446 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700447 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700448 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800449 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700450
James Feist0cd014a2019-04-08 15:04:33 -0700451 uint8_t thresholds = 0;
452
453 auto warningObject =
454 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
455 if (warningObject != sensorMap.end())
456 {
457 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
458 auto alarmLow = warningObject->second.find("WarningAlarmLow");
459 if (alarmHigh != warningObject->second.end())
460 {
461 if (std::get<bool>(alarmHigh->second))
462 {
463 thresholds |= static_cast<uint8_t>(
464 IPMISensorReadingByte3::upperNonCritical);
465 }
466 }
467 if (alarmLow != warningObject->second.end())
468 {
469 if (std::get<bool>(alarmLow->second))
470 {
471 thresholds |= static_cast<uint8_t>(
472 IPMISensorReadingByte3::lowerNonCritical);
473 }
474 }
475 }
476
477 auto criticalObject =
478 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
479 if (criticalObject != sensorMap.end())
480 {
481 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
482 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
483 if (alarmHigh != criticalObject->second.end())
484 {
485 if (std::get<bool>(alarmHigh->second))
486 {
487 thresholds |=
488 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
489 }
490 }
491 if (alarmLow != criticalObject->second.end())
492 {
493 if (std::get<bool>(alarmLow->second))
494 {
495 thresholds |=
496 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
497 }
498 }
499 }
500
501 // no discrete as of today so optional byte is never returned
502 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700503}
504
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000505/** @brief implements the Set Sensor threshold command
506 * @param sensorNumber - sensor number
507 * @param lowerNonCriticalThreshMask
508 * @param lowerCriticalThreshMask
509 * @param lowerNonRecovThreshMask
510 * @param upperNonCriticalThreshMask
511 * @param upperCriticalThreshMask
512 * @param upperNonRecovThreshMask
513 * @param reserved
514 * @param lowerNonCritical - lower non-critical threshold
515 * @param lowerCritical - Lower critical threshold
516 * @param lowerNonRecoverable - Lower non recovarable threshold
517 * @param upperNonCritical - Upper non-critical threshold
518 * @param upperCritical - Upper critical
519 * @param upperNonRecoverable - Upper Non-recoverable
520 *
521 * @returns IPMI completion code
522 */
523ipmi::RspType<> ipmiSenSetSensorThresholds(
524 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
525 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
526 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
527 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
528 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
529 uint8_t upperNonCritical, uint8_t upperCritical,
530 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700531{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000532 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700533
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000534 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700535 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000536 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700537 }
538
539 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000540 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700541 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000542 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700543 }
544
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000545 // if none of the threshold mask are set, nothing to do
546 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
547 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
548 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700549 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000550 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700551 }
552
553 std::string connection;
554 std::string path;
555
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000556 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700557 if (status)
558 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000559 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700560 }
561 SensorMap sensorMap;
562 if (!getSensorMap(connection, path, sensorMap))
563 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000564 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700565 }
566
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700567 double max = 0;
568 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700569 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700570
571 int16_t mValue = 0;
572 int16_t bValue = 0;
573 int8_t rExp = 0;
574 int8_t bExp = 0;
575 bool bSigned = false;
576
577 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
578 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000579 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700580 }
581
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700582 // store a vector of property name, value to set, and interface
583 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
584
585 // define the indexes of the tuple
586 constexpr uint8_t propertyName = 0;
587 constexpr uint8_t thresholdValue = 1;
588 constexpr uint8_t interface = 2;
589 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000590 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700591 {
592 auto findThreshold =
593 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
594 if (findThreshold == sensorMap.end())
595 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000596 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700597 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000598 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700599 {
600 auto findLower = findThreshold->second.find("CriticalLow");
601 if (findLower == findThreshold->second.end())
602 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000603 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700604 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000605 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700606 findThreshold->first);
607 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000608 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700609 {
610 auto findUpper = findThreshold->second.find("CriticalHigh");
611 if (findUpper == findThreshold->second.end())
612 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000613 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700614 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000615 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700616 findThreshold->first);
617 }
618 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000619 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620 {
621 auto findThreshold =
622 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
623 if (findThreshold == sensorMap.end())
624 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000625 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700626 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 {
629 auto findLower = findThreshold->second.find("WarningLow");
630 if (findLower == findThreshold->second.end())
631 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000632 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700633 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000634 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700635 findThreshold->first);
636 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000637 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700638 {
639 auto findUpper = findThreshold->second.find("WarningHigh");
640 if (findUpper == findThreshold->second.end())
641 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000642 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700643 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000644 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700645 findThreshold->first);
646 }
647 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700648 for (const auto &property : thresholdsToSet)
649 {
650 // from section 36.3 in the IPMI Spec, assume all linear
651 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
652 (bValue * std::pow(10, bExp))) *
653 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700654 setDbusProperty(
655 *getSdBus(), connection, path, std::get<interface>(property),
656 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700657 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000658 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700659}
660
James Feist902c4c52019-04-16 14:51:31 -0700661IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700662{
James Feist902c4c52019-04-16 14:51:31 -0700663 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700664 auto warningInterface =
665 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
666 auto criticalInterface =
667 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
668
669 if ((warningInterface != sensorMap.end()) ||
670 (criticalInterface != sensorMap.end()))
671 {
672 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
673
674 if (sensorPair == sensorMap.end())
675 {
676 // should not have been able to find a sensor not implementing
677 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700678 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700679 }
680
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800681 double max = 0;
682 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700683 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700684
685 int16_t mValue = 0;
686 int16_t bValue = 0;
687 int8_t rExp = 0;
688 int8_t bExp = 0;
689 bool bSigned = false;
690
691 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
692 {
James Feist902c4c52019-04-16 14:51:31 -0700693 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700694 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700695 if (warningInterface != sensorMap.end())
696 {
697 auto &warningMap = warningInterface->second;
698
699 auto warningHigh = warningMap.find("WarningHigh");
700 auto warningLow = warningMap.find("WarningLow");
701
702 if (warningHigh != warningMap.end())
703 {
James Feist902c4c52019-04-16 14:51:31 -0700704
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700705 double value =
706 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700707 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700708 value, mValue, rExp, bValue, bExp, bSigned);
709 }
710 if (warningLow != warningMap.end())
711 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700712 double value =
713 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700714 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700715 value, mValue, rExp, bValue, bExp, bSigned);
716 }
717 }
718 if (criticalInterface != sensorMap.end())
719 {
720 auto &criticalMap = criticalInterface->second;
721
722 auto criticalHigh = criticalMap.find("CriticalHigh");
723 auto criticalLow = criticalMap.find("CriticalLow");
724
725 if (criticalHigh != criticalMap.end())
726 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700727 double value =
728 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700729 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700730 value, mValue, rExp, bValue, bExp, bSigned);
731 }
732 if (criticalLow != criticalMap.end())
733 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700734 double value =
735 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700736 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700737 value, mValue, rExp, bValue, bExp, bSigned);
738 }
739 }
740 }
James Feist902c4c52019-04-16 14:51:31 -0700741 return resp;
742}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700743
James Feist902c4c52019-04-16 14:51:31 -0700744ipmi::RspType<uint8_t, // readable
745 uint8_t, // lowerNCrit
746 uint8_t, // lowerCrit
747 uint8_t, // lowerNrecoverable
748 uint8_t, // upperNC
749 uint8_t, // upperCrit
750 uint8_t> // upperNRecoverable
751 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
752{
753 std::string connection;
754 std::string path;
755
756 auto status = getSensorConnection(sensorNumber, connection, path);
757 if (status)
758 {
759 return ipmi::response(status);
760 }
761
762 SensorMap sensorMap;
763 if (!getSensorMap(connection, path, sensorMap))
764 {
765 return ipmi::responseResponseError();
766 }
767
768 IPMIThresholds thresholdData;
769 try
770 {
771 thresholdData = getIPMIThresholds(sensorMap);
772 }
773 catch (std::exception &)
774 {
775 return ipmi::responseResponseError();
776 }
777
778 uint8_t readable = 0;
779 uint8_t lowerNC = 0;
780 uint8_t lowerCritical = 0;
781 uint8_t lowerNonRecoverable = 0;
782 uint8_t upperNC = 0;
783 uint8_t upperCritical = 0;
784 uint8_t upperNonRecoverable = 0;
785
786 if (thresholdData.warningHigh)
787 {
788 readable |=
789 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
790 upperNC = *thresholdData.warningHigh;
791 }
792 if (thresholdData.warningLow)
793 {
794 readable |=
795 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
796 lowerNC = *thresholdData.warningLow;
797 }
798
799 if (thresholdData.criticalHigh)
800 {
801 readable |=
802 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
803 upperCritical = *thresholdData.criticalHigh;
804 }
805 if (thresholdData.criticalLow)
806 {
807 readable |=
808 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
809 lowerCritical = *thresholdData.criticalLow;
810 }
811
812 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
813 lowerNonRecoverable, upperNC, upperCritical,
814 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700815}
816
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000817/** @brief implements the get Sensor event enable command
818 * @param sensorNumber - sensor number
819 *
820 * @returns IPMI completion code plus response data
821 * - enabled - Sensor Event messages
822 * - assertionEnabledLsb - Assertion event messages
823 * - assertionEnabledMsb - Assertion event messages
824 * - deassertionEnabledLsb - Deassertion event messages
825 * - deassertionEnabledMsb - Deassertion event messages
826 */
827
828ipmi::RspType<uint8_t, // enabled
829 uint8_t, // assertionEnabledLsb
830 uint8_t, // assertionEnabledMsb
831 uint8_t, // deassertionEnabledLsb
832 uint8_t> // deassertionEnabledMsb
833 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700834{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700835 std::string connection;
836 std::string path;
837
Patrick Venturea41714c2019-09-25 16:59:41 -0700838 uint8_t enabled = 0;
839 uint8_t assertionEnabledLsb = 0;
840 uint8_t assertionEnabledMsb = 0;
841 uint8_t deassertionEnabledLsb = 0;
842 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000843
844 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700845 if (status)
846 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000847 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700848 }
849
850 SensorMap sensorMap;
851 if (!getSensorMap(connection, path, sensorMap))
852 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000853 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700854 }
855
856 auto warningInterface =
857 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
858 auto criticalInterface =
859 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700860 if ((warningInterface != sensorMap.end()) ||
861 (criticalInterface != sensorMap.end()))
862 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000863 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700864 IPMISensorEventEnableByte2::sensorScanningEnable);
865 if (warningInterface != sensorMap.end())
866 {
867 auto &warningMap = warningInterface->second;
868
869 auto warningHigh = warningMap.find("WarningHigh");
870 auto warningLow = warningMap.find("WarningLow");
871 if (warningHigh != warningMap.end())
872 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000873 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700874 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000875 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700876 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
877 }
878 if (warningLow != warningMap.end())
879 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000880 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700881 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000882 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700883 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
884 }
885 }
886 if (criticalInterface != sensorMap.end())
887 {
888 auto &criticalMap = criticalInterface->second;
889
890 auto criticalHigh = criticalMap.find("CriticalHigh");
891 auto criticalLow = criticalMap.find("CriticalLow");
892
893 if (criticalHigh != criticalMap.end())
894 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000895 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700896 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000897 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700898 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
899 }
900 if (criticalLow != criticalMap.end())
901 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000902 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700903 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000904 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700905 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
906 }
907 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700908 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000909
910 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
911 assertionEnabledMsb, deassertionEnabledLsb,
912 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700913}
914
915ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
916 ipmi_request_t request,
917 ipmi_response_t response,
918 ipmi_data_len_t dataLen,
919 ipmi_context_t context)
920{
921 if (*dataLen != 1)
922 {
923 *dataLen = 0;
924 return IPMI_CC_REQ_DATA_LEN_INVALID;
925 }
926 *dataLen = 0; // default to 0 in case of an error
927
928 uint8_t sensnum = *(static_cast<uint8_t *>(request));
929
930 std::string connection;
931 std::string path;
932
933 auto status = getSensorConnection(sensnum, connection, path);
934 if (status)
935 {
936 return status;
937 }
938
939 SensorMap sensorMap;
940 if (!getSensorMap(connection, path, sensorMap))
941 {
942 return IPMI_CC_RESPONSE_ERROR;
943 }
944
945 auto warningInterface =
946 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
947 auto criticalInterface =
948 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
949
950 // zero out response buff
951 auto responseClear = static_cast<uint8_t *>(response);
952 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
953 auto resp = static_cast<SensorEventStatusResp *>(response);
954 resp->enabled =
955 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
956
James Feist392786a2019-03-19 13:36:10 -0700957 std::optional<bool> criticalDeassertHigh =
958 thresholdDeassertMap[path]["CriticalAlarmHigh"];
959 std::optional<bool> criticalDeassertLow =
960 thresholdDeassertMap[path]["CriticalAlarmLow"];
961 std::optional<bool> warningDeassertHigh =
962 thresholdDeassertMap[path]["WarningAlarmHigh"];
963 std::optional<bool> warningDeassertLow =
964 thresholdDeassertMap[path]["WarningAlarmLow"];
965
966 if (criticalDeassertHigh && !*criticalDeassertHigh)
967 {
968 resp->deassertionsMSB |= static_cast<uint8_t>(
969 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
970 }
971 if (criticalDeassertLow && !*criticalDeassertLow)
972 {
973 resp->deassertionsMSB |= static_cast<uint8_t>(
974 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
975 }
976 if (warningDeassertHigh && !*warningDeassertHigh)
977 {
978 resp->deassertionsLSB |= static_cast<uint8_t>(
979 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
980 }
981 if (warningDeassertLow && !*warningDeassertLow)
982 {
983 resp->deassertionsLSB |= static_cast<uint8_t>(
984 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
985 }
986
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700987 if ((warningInterface != sensorMap.end()) ||
988 (criticalInterface != sensorMap.end()))
989 {
990 resp->enabled = static_cast<uint8_t>(
991 IPMISensorEventEnableByte2::eventMessagesEnable);
992 if (warningInterface != sensorMap.end())
993 {
994 auto &warningMap = warningInterface->second;
995
996 auto warningHigh = warningMap.find("WarningAlarmHigh");
997 auto warningLow = warningMap.find("WarningAlarmLow");
998 auto warningHighAlarm = false;
999 auto warningLowAlarm = false;
1000
1001 if (warningHigh != warningMap.end())
1002 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001003 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001004 }
1005 if (warningLow != warningMap.end())
1006 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001007 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001008 }
1009 if (warningHighAlarm)
1010 {
1011 resp->assertionsLSB |= static_cast<uint8_t>(
1012 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1013 }
1014 if (warningLowAlarm)
1015 {
1016 resp->assertionsLSB |= 1; // lower nc going low
1017 }
1018 }
1019 if (criticalInterface != sensorMap.end())
1020 {
1021 auto &criticalMap = criticalInterface->second;
1022
1023 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1024 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1025 auto criticalHighAlarm = false;
1026 auto criticalLowAlarm = false;
1027
1028 if (criticalHigh != criticalMap.end())
1029 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001030 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001031 }
1032 if (criticalLow != criticalMap.end())
1033 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001034 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001035 }
1036 if (criticalHighAlarm)
1037 {
1038 resp->assertionsMSB |= static_cast<uint8_t>(
1039 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1040 }
1041 if (criticalLowAlarm)
1042 {
1043 resp->assertionsLSB |= static_cast<uint8_t>(
1044 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1045 }
1046 }
1047 *dataLen = sizeof(SensorEventStatusResp);
1048 }
1049
1050 // no thresholds enabled, don't need assertionMSB
1051 else
1052 {
1053 *dataLen = sizeof(SensorEventStatusResp) - 1;
1054 }
1055
1056 return IPMI_CC_OK;
1057}
1058
1059/* end sensor commands */
1060
1061/* storage commands */
1062
James Feist74c50c62019-08-14 14:18:41 -07001063ipmi::RspType<uint8_t, // sdr version
1064 uint16_t, // record count
1065 uint16_t, // free space
1066 uint32_t, // most recent addition
1067 uint32_t, // most recent erase
1068 uint8_t // operationSupport
1069 >
1070 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001071{
James Feist74c50c62019-08-14 14:18:41 -07001072 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001073 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1074 {
James Feist74c50c62019-08-14 14:18:41 -07001075 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001076 }
1077
James Feist74c50c62019-08-14 14:18:41 -07001078 size_t fruCount = 0;
1079 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1080 if (ret != ipmi::ccSuccess)
1081 {
1082 return ipmi::response(ret);
1083 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001084
James Feist74c50c62019-08-14 14:18:41 -07001085 uint16_t recordCount =
1086 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001087
James Feist74c50c62019-08-14 14:18:41 -07001088 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001090
1091 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001092 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001093 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001094 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001095 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1096 unspecifiedFreeSpace, sdrLastAdd,
1097 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001098}
1099
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001100/** @brief implements the get SDR allocation info command
1101 *
1102 * @returns IPMI completion code plus response data
1103 * - allocUnits - Number of possible allocation units
1104 * - allocUnitSize - Allocation unit size in bytes.
1105 * - allocUnitFree - Number of free allocation units
1106 * - allocUnitLargestFree - Largest free block in allocation units
1107 * - maxRecordSize - Maximum record size in allocation units.
1108 */
1109ipmi::RspType<uint16_t, // allocUnits
1110 uint16_t, // allocUnitSize
1111 uint16_t, // allocUnitFree
1112 uint16_t, // allocUnitLargestFree
1113 uint8_t // maxRecordSize
1114 >
1115 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001116{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001117 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001118 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001119
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001120 constexpr uint16_t allocUnitFree = 0;
1121 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001122 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001123 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001124
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001125 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1126 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001127}
1128
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001129/** @brief implements the reserve SDR command
1130 * @returns IPMI completion code plus response data
1131 * - sdrReservationID
1132 */
1133ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001134{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001135 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001136 if (sdrReservationID == 0)
1137 {
1138 sdrReservationID++;
1139 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001140
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001141 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001142}
1143
James Feistb49a98a2019-04-16 13:48:09 -07001144ipmi::RspType<uint16_t, // next record ID
1145 std::vector<uint8_t> // payload
1146 >
1147 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1148 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001149{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001150 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001151
1152 // reservation required for partial reads with non zero offset into
1153 // record
James Feistb49a98a2019-04-16 13:48:09 -07001154 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001155 {
James Feistb49a98a2019-04-16 13:48:09 -07001156 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001157 }
1158
1159 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1160 {
James Feistb49a98a2019-04-16 13:48:09 -07001161 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001162 }
1163
1164 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001165 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1166 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167 {
James Feistb49a98a2019-04-16 13:48:09 -07001168 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001169 }
1170
James Feist74c50c62019-08-14 14:18:41 -07001171 size_t lastRecord =
1172 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001173 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001174 {
James Feistb49a98a2019-04-16 13:48:09 -07001175 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001176 }
James Feistb49a98a2019-04-16 13:48:09 -07001177 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001178 {
James Feistb49a98a2019-04-16 13:48:09 -07001179 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001180 }
1181
James Feistb49a98a2019-04-16 13:48:09 -07001182 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001183
James Feistb49a98a2019-04-16 13:48:09 -07001184 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001185 {
James Feist74c50c62019-08-14 14:18:41 -07001186 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001187 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001188 if (fruIndex >= fruCount)
1189 {
James Feist74c50c62019-08-14 14:18:41 -07001190 // handle type 12 hardcoded records
1191 size_t type12Index = fruIndex - fruCount;
1192 if (type12Index >= ipmi::storage::type12Count ||
1193 offset > sizeof(Type12Record))
1194 {
1195 return ipmi::responseInvalidFieldRequest();
1196 }
1197 std::vector<uint8_t> record =
1198 ipmi::storage::getType12SDRs(type12Index, recordID);
1199 if (record.size() < (offset + bytesToRead))
1200 {
1201 bytesToRead = record.size() - offset;
1202 }
James Feistb49a98a2019-04-16 13:48:09 -07001203
James Feist74c50c62019-08-14 14:18:41 -07001204 recordData.insert(recordData.end(), record.begin() + offset,
1205 record.begin() + offset + bytesToRead);
1206 }
1207 else
1208 {
1209 // handle fru records
1210 get_sdr::SensorDataFruRecord data;
1211 if (offset > sizeof(data))
1212 {
1213 return ipmi::responseInvalidFieldRequest();
1214 }
1215 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1216 if (ret != IPMI_CC_OK)
1217 {
1218 return ipmi::response(ret);
1219 }
1220 data.header.record_id_msb = recordID << 8;
1221 data.header.record_id_lsb = recordID & 0xFF;
1222 if (sizeof(data) < (offset + bytesToRead))
1223 {
1224 bytesToRead = sizeof(data) - offset;
1225 }
1226
1227 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1228 recordData.insert(recordData.end(), respStart,
1229 respStart + bytesToRead);
1230 }
James Feistb49a98a2019-04-16 13:48:09 -07001231
1232 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001233 }
1234
1235 std::string connection;
1236 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001237 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001238 for (const auto &sensor : sensorTree)
1239 {
1240 if (sensorIndex-- == 0)
1241 {
1242 if (!sensor.second.size())
1243 {
James Feistb49a98a2019-04-16 13:48:09 -07001244 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001245 }
1246 connection = sensor.second.begin()->first;
1247 path = sensor.first;
1248 break;
1249 }
1250 }
1251
1252 SensorMap sensorMap;
1253 if (!getSensorMap(connection, path, sensorMap))
1254 {
James Feistb49a98a2019-04-16 13:48:09 -07001255 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001256 }
James Feistb49a98a2019-04-16 13:48:09 -07001257 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001258 get_sdr::SensorDataFullRecord record = {0};
1259
James Feistb49a98a2019-04-16 13:48:09 -07001260 record.header.record_id_msb = recordID << 8;
1261 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001262 record.header.sdr_version = ipmiSdrVersion;
1263 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1264 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1265 sizeof(get_sdr::SensorDataRecordHeader);
1266 record.key.owner_id = 0x20;
1267 record.key.owner_lun = 0x0;
1268 record.key.sensor_number = sensornumber;
1269
1270 record.body.entity_id = 0x0;
1271 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001272 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001273 record.body.sensor_type = getSensorTypeFromPath(path);
1274 std::string type = getSensorTypeStringFromPath(path);
1275 auto typeCstr = type.c_str();
1276 auto findUnits = sensorUnits.find(typeCstr);
1277 if (findUnits != sensorUnits.end())
1278 {
1279 record.body.sensor_units_2_base =
1280 static_cast<uint8_t>(findUnits->second);
1281 } // else default 0x0 unspecified
1282
1283 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1284
1285 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1286 if (sensorObject == sensorMap.end())
1287 {
James Feistb49a98a2019-04-16 13:48:09 -07001288 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001289 }
1290
1291 auto maxObject = sensorObject->second.find("MaxValue");
1292 auto minObject = sensorObject->second.find("MinValue");
1293 double max = 128;
1294 double min = -127;
1295 if (maxObject != sensorObject->second.end())
1296 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001297 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001298 }
1299
1300 if (minObject != sensorObject->second.end())
1301 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001302 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001303 }
1304
Yong Li1f2eb5e2019-05-23 14:07:17 +08001305 int16_t mValue = 0;
1306 int8_t rExp = 0;
1307 int16_t bValue = 0;
1308 int8_t bExp = 0;
1309 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001310
1311 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1312 {
James Feistb49a98a2019-04-16 13:48:09 -07001313 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001314 }
1315
1316 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1317 record.body.m_lsb = mValue & 0xFF;
1318
1319 // move the smallest bit of the MSB into place (bit 9)
1320 // the MSbs are bits 7:8 in m_msb_and_tolerance
1321 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1322
1323 // assign the negative
1324 if (mValue < 0)
1325 {
1326 mMsb |= (1 << 7);
1327 }
1328 record.body.m_msb_and_tolerance = mMsb;
1329
1330 record.body.b_lsb = bValue & 0xFF;
1331
1332 // move the smallest bit of the MSB into place
1333 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1334 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1335
1336 // assign the negative
1337 if (bValue < 0)
1338 {
1339 bMsb |= (1 << 7);
1340 }
1341 record.body.b_msb_and_accuracy_lsb = bMsb;
1342
1343 record.body.r_b_exponents = bExp & 0x7;
1344 if (bExp < 0)
1345 {
1346 record.body.r_b_exponents |= 1 << 3;
1347 }
1348 record.body.r_b_exponents = (rExp & 0x7) << 4;
1349 if (rExp < 0)
1350 {
1351 record.body.r_b_exponents |= 1 << 7;
1352 }
1353
1354 // todo fill out rest of units
1355 if (bSigned)
1356 {
1357 record.body.sensor_units_1 = 1 << 7;
1358 }
1359
1360 // populate sensor name from path
1361 std::string name;
1362 size_t nameStart = path.rfind("/");
1363 if (nameStart != std::string::npos)
1364 {
1365 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1366 }
1367
1368 std::replace(name.begin(), name.end(), '_', ' ');
1369 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1370 {
James Feist979a2322019-05-15 09:06:54 -07001371 // try to not truncate by replacing common words
1372 constexpr std::array<std::pair<const char *, const char *>, 2>
1373 replaceWords = {std::make_pair("Output", "Out"),
1374 std::make_pair("Input", "In")};
1375 for (const auto &[find, replace] : replaceWords)
1376 {
1377 boost::replace_all(name, find, replace);
1378 }
1379
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001380 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1381 }
1382 record.body.id_string_info = name.size();
1383 std::strncpy(record.body.id_string, name.c_str(),
1384 sizeof(record.body.id_string));
1385
James Feistc4b15bc2019-04-16 15:41:39 -07001386 IPMIThresholds thresholdData;
1387 try
1388 {
1389 thresholdData = getIPMIThresholds(sensorMap);
1390 }
1391 catch (std::exception &)
1392 {
1393 return ipmi::responseResponseError();
1394 }
1395
1396 if (thresholdData.criticalHigh)
1397 {
1398 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1399 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1400 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1401 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1402 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1403 record.body.discrete_reading_setting_mask[0] |=
1404 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1405 }
1406 if (thresholdData.warningHigh)
1407 {
1408 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1409 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1410 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1411 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1412 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1413 record.body.discrete_reading_setting_mask[0] |=
1414 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1415 }
1416 if (thresholdData.criticalLow)
1417 {
1418 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1419 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1420 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1421 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1422 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1423 record.body.discrete_reading_setting_mask[0] |=
1424 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1425 }
1426 if (thresholdData.warningLow)
1427 {
1428 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1429 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1430 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1431 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1432 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1433 record.body.discrete_reading_setting_mask[0] |=
1434 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1435 }
1436
1437 // everything that is readable is setable
1438 record.body.discrete_reading_setting_mask[1] =
1439 record.body.discrete_reading_setting_mask[0];
1440
James Feistb49a98a2019-04-16 13:48:09 -07001441 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001442 {
James Feistb49a98a2019-04-16 13:48:09 -07001443 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001444 }
1445
James Feistb49a98a2019-04-16 13:48:09 -07001446 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1447 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001448
James Feistb49a98a2019-04-16 13:48:09 -07001449 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001450}
1451/* end storage commands */
1452
1453void registerSensorFunctions()
1454{
1455 // get firmware version information
1456 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1457 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1458
1459 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001460 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1461 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001462
1463 // <Set Sensor Reading and Event Status>
1464 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001465 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001466 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1467
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001468 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001469 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1470 ipmi::sensor_event::cmdPlatformEvent,
1471 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001472
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001473 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001474 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1475 ipmi::sensor_event::cmdGetSensorReading,
1476 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001477
1478 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001479 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1480 ipmi::sensor_event::cmdGetSensorThreshold,
1481 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001482
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001483 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001484 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1485 ipmi::sensor_event::cmdSetSensorThreshold,
1486 ipmi::Privilege::Operator,
1487 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001488
1489 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001490 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1491 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001492 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001493
1494 // <Get Sensor Event Status>
1495 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001496 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1497 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001498
1499 // register all storage commands for both Sensor and Storage command
1500 // versions
1501
1502 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001503 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1504 ipmi::storage::cmdGetSdrRepositoryInfo,
1505 ipmi::Privilege::User,
1506 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001507
1508 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001509 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1510 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1511 ipmi::Privilege::User,
1512 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001513
1514 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001515 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1516 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001517 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001518
Vernon Mauery98bbf692019-09-16 11:14:59 -07001519 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1520 ipmi::storage::cmdReserveSdrRepository,
1521 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001522
1523 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001524 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1525 ipmi::sensor_event::cmdGetDeviceSdr,
1526 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001527
Vernon Mauery98bbf692019-09-16 11:14:59 -07001528 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1529 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1530 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001531}
1532} // namespace ipmi