blob: c4801d53cf67b8ac4f78ac09e4ba92095e85894f [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>
Patrick Venture44ec88e2019-09-25 17:48:29 -070018#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070019#include <boost/algorithm/string.hpp>
20#include <boost/container/flat_map.hpp>
21#include <chrono>
22#include <cmath>
23#include <commandutils.hpp>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070024#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070025#include <iostream>
Jason M. Bills99b78ec2019-01-18 10:42:18 -080026#include <ipmi_to_redfish_hooks.hpp>
James Feist2a265d52019-04-08 11:16:27 -070027#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070028#include <ipmid/utils.hpp>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070029#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070030#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070031#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070032#include <phosphor-logging/log.hpp>
33#include <sdbusplus/bus.hpp>
34#include <sdrutils.hpp>
35#include <sensorcommands.hpp>
36#include <sensorutils.hpp>
37#include <storagecommands.hpp>
38#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070039#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070040#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070041
42namespace ipmi
43{
44using ManagedObjectType =
45 std::map<sdbusplus::message::object_path,
46 std::map<std::string, std::map<std::string, DbusVariant>>>;
47
48using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
49
50static constexpr int sensorListUpdatePeriod = 10;
51static constexpr int sensorMapUpdatePeriod = 2;
52
53constexpr size_t maxSDRTotalSize =
54 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
55constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
56
57static uint16_t sdrReservationID;
58static uint32_t sdrLastAdd = noTimestamp;
59static uint32_t sdrLastRemove = noTimestamp;
60
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053061SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070062static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
63
Jason M. Bills17add592018-11-12 14:30:12 -080064// Specify the comparison required to sort and find char* map objects
65struct CmpStr
66{
67 bool operator()(const char *a, const char *b) const
68 {
69 return std::strcmp(a, b) < 0;
70 }
71};
72const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
73 sensorUnits{{{"temperature", SensorUnits::degreesC},
74 {"voltage", SensorUnits::volts},
75 {"current", SensorUnits::amps},
76 {"fan_tach", SensorUnits::rpm},
77 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070078
79void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070080
81static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070082 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070083 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
84 "sensors/'",
85 [](sdbusplus::message::message &m) {
86 sensorTree.clear();
87 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
88 std::chrono::system_clock::now().time_since_epoch())
89 .count();
90 });
91
92static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070093 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070094 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
95 "sensors/'",
96 [](sdbusplus::message::message &m) {
97 sensorTree.clear();
98 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
99 std::chrono::system_clock::now().time_since_epoch())
100 .count();
101 });
102
James Feist392786a2019-03-19 13:36:10 -0700103// this keeps track of deassertions for sensor event status command. A
104// deasertion can only happen if an assertion was seen first.
105static boost::container::flat_map<
106 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
107 thresholdDeassertMap;
108
109static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700110 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700111 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
112 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
113 [](sdbusplus::message::message &m) {
114 boost::container::flat_map<std::string, std::variant<bool, double>>
115 values;
116 m.read(std::string(), values);
117
118 auto findAssert =
119 std::find_if(values.begin(), values.end(), [](const auto &pair) {
120 return pair.first.find("Alarm") != std::string::npos;
121 });
122 if (findAssert != values.end())
123 {
124 auto ptr = std::get_if<bool>(&(findAssert->second));
125 if (ptr == nullptr)
126 {
127 phosphor::logging::log<phosphor::logging::level::ERR>(
128 "thresholdChanged: Assert non bool");
129 return;
130 }
131 if (*ptr)
132 {
133 phosphor::logging::log<phosphor::logging::level::INFO>(
134 "thresholdChanged: Assert",
135 phosphor::logging::entry("SENSOR=%s", m.get_path()));
136 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
137 }
138 else
139 {
140 auto &value =
141 thresholdDeassertMap[m.get_path()][findAssert->first];
142 if (value)
143 {
144 phosphor::logging::log<phosphor::logging::level::INFO>(
145 "thresholdChanged: deassert",
146 phosphor::logging::entry("SENSOR=%s", m.get_path()));
147 value = *ptr;
148 }
149 }
150 }
151 });
152
James Feistaecaef72019-04-26 10:30:32 -0700153static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
154 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700155{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700156 max = 127;
157 min = -128;
158
James Feistaecaef72019-04-26 10:30:32 -0700159 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
160 auto critical =
161 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
162 auto warning =
163 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
164
165 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700166 {
James Feistaecaef72019-04-26 10:30:32 -0700167 auto maxMap = sensorObject->second.find("MaxValue");
168 auto minMap = sensorObject->second.find("MinValue");
169
170 if (maxMap != sensorObject->second.end())
171 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700172 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700173 }
174 if (minMap != sensorObject->second.end())
175 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700176 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700177 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700178 }
James Feistaecaef72019-04-26 10:30:32 -0700179 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700180 {
James Feistaecaef72019-04-26 10:30:32 -0700181 auto lower = critical->second.find("CriticalLow");
182 auto upper = critical->second.find("CriticalHigh");
183 if (lower != critical->second.end())
184 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700185 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700186 min = std::min(value, min);
187 }
188 if (upper != critical->second.end())
189 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700190 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700191 max = std::max(value, max);
192 }
193 }
194 if (warning != sensorMap.end())
195 {
196
197 auto lower = warning->second.find("WarningLow");
198 auto upper = warning->second.find("WarningHigh");
199 if (lower != warning->second.end())
200 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700201 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700202 min = std::min(value, min);
203 }
204 if (upper != warning->second.end())
205 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700206 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700207 max = std::max(value, max);
208 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700209 }
210}
211
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700212static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
213 SensorMap &sensorMap)
214{
215 static boost::container::flat_map<
216 std::string, std::chrono::time_point<std::chrono::steady_clock>>
217 updateTimeMap;
218
219 auto updateFind = updateTimeMap.find(sensorConnection);
220 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
221 if (updateFind != updateTimeMap.end())
222 {
223 lastUpdate = updateFind->second;
224 }
225
226 auto now = std::chrono::steady_clock::now();
227
228 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
229 .count() > sensorMapUpdatePeriod)
230 {
231 updateTimeMap[sensorConnection] = now;
232
Vernon Mauery15419dd2019-05-24 09:40:30 -0700233 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
234 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700235 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
236 "GetManagedObjects");
237
238 ManagedObjectType managedObjects;
239 try
240 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700241 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700242 reply.read(managedObjects);
243 }
244 catch (sdbusplus::exception_t &)
245 {
246 phosphor::logging::log<phosphor::logging::level::ERR>(
247 "Error getting managed objects from connection",
248 phosphor::logging::entry("CONNECTION=%s",
249 sensorConnection.c_str()));
250 return false;
251 }
252
253 SensorCache[sensorConnection] = managedObjects;
254 }
255 auto connection = SensorCache.find(sensorConnection);
256 if (connection == SensorCache.end())
257 {
258 return false;
259 }
260 auto path = connection->second.find(sensorPath);
261 if (path == connection->second.end())
262 {
263 return false;
264 }
265 sensorMap = path->second;
266
267 return true;
268}
269
270/* sensor commands */
271ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
272 ipmi_request_t request,
273 ipmi_response_t response,
274 ipmi_data_len_t dataLen,
275 ipmi_context_t context)
276{
277 *dataLen = 0;
278 printCommand(+netfn, +cmd);
279 return IPMI_CC_INVALID;
280}
281
James Feist7aaf3fe2019-06-25 11:52:11 -0700282namespace meHealth
283{
284constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
285constexpr const char *path = "/xyz/openbmc_project/status/me";
286constexpr const char *interface = "xyz.openbmc_project.SetHealth";
287constexpr const char *method = "SetHealth";
288constexpr const char *critical = "critical";
289constexpr const char *warning = "warning";
290constexpr const char *ok = "ok";
291} // namespace meHealth
292
293static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
294{
295 constexpr const std::array<uint8_t, 10> critical = {
296 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
297 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
298 0x1A};
299
300 std::string state;
301 if (std::find(critical.begin(), critical.end(), eventData2) !=
302 critical.end())
303 {
304 state = meHealth::critical;
305 }
306 // special case 0x3 as we only care about a few states
307 else if (eventData2 == 0x3)
308 {
309 if (eventData3 <= 0x2)
310 {
311 state = meHealth::warning;
312 }
313 else
314 {
315 return;
316 }
317 }
318 else if (std::find(warning.begin(), warning.end(), eventData2) !=
319 warning.end())
320 {
321 state = meHealth::warning;
322 }
323 else
324 {
325 return;
326 }
327 if (disable)
328 {
329 state = meHealth::ok;
330 }
331
332 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
333 auto setHealth =
334 dbus->new_method_call(meHealth::busname, meHealth::path,
335 meHealth::interface, meHealth::method);
336 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
337 try
338 {
339 dbus->call(setHealth);
340 }
341 catch (sdbusplus::exception_t &)
342 {
343 phosphor::logging::log<phosphor::logging::level::ERR>(
344 "Failed to set ME Health");
345 }
346}
347
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700348ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
349{
James Feist7aaf3fe2019-06-25 11:52:11 -0700350 constexpr const uint8_t meId = 0x2C;
351 constexpr const uint8_t meSensorNum = 0x17;
352 constexpr const uint8_t disabled = 0x80;
353
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700354 uint8_t generatorID = 0;
355 uint8_t evmRev = 0;
356 uint8_t sensorType = 0;
357 uint8_t sensorNum = 0;
358 uint8_t eventType = 0;
359 uint8_t eventData1 = 0;
360 std::optional<uint8_t> eventData2 = 0;
361 std::optional<uint8_t> eventData3 = 0;
362
363 // todo: This check is supposed to be based on the incoming channel.
364 // e.g. system channel will provide upto 8 bytes including generator
365 // ID, but ipmb channel will provide only up to 7 bytes without the
366 // generator ID.
367 // Support for this check is coming in future patches, so for now just base
368 // it on if the first byte is the EvMRev (0x04).
369 if (p.size() && p.data()[0] == 0x04)
370 {
371 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
372 eventData2, eventData3);
373 // todo: the generator ID for this channel is supposed to come from the
374 // IPMB requesters slave address. Support for this is coming in future
375 // patches, so for now just assume it is coming from the ME (0x2C).
376 generatorID = 0x2C;
377 }
378 else
379 {
380 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
381 eventData1, eventData2, eventData3);
382 }
383 if (!p.fullyUnpacked())
384 {
385 return ipmi::responseReqDataLenInvalid();
386 }
387
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700388 // Send this request to the Redfish hooks to log it as a Redfish message
389 // instead. There is no need to add it to the SEL, so just return success.
390 intel_oem::ipmi::sel::checkRedfishHooks(
391 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
392 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700393
James Feist7aaf3fe2019-06-25 11:52:11 -0700394 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
395 eventData3)
396 {
397 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
398 }
399
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700400 return ipmi::responseSuccess();
401}
402
James Feist0cd014a2019-04-08 15:04:33 -0700403ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
404 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700405{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700406 std::string connection;
407 std::string path;
408
409 auto status = getSensorConnection(sensnum, connection, path);
410 if (status)
411 {
James Feist0cd014a2019-04-08 15:04:33 -0700412 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700413 }
414
415 SensorMap sensorMap;
416 if (!getSensorMap(connection, path, sensorMap))
417 {
James Feist0cd014a2019-04-08 15:04:33 -0700418 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700419 }
420 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
421
422 if (sensorObject == sensorMap.end() ||
423 sensorObject->second.find("Value") == sensorObject->second.end())
424 {
James Feist0cd014a2019-04-08 15:04:33 -0700425 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700426 }
James Feist0cd014a2019-04-08 15:04:33 -0700427 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700428 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700429
Yong Li1f2eb5e2019-05-23 14:07:17 +0800430 double max = 0;
431 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700432 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700433
434 int16_t mValue = 0;
435 int16_t bValue = 0;
436 int8_t rExp = 0;
437 int8_t bExp = 0;
438 bool bSigned = false;
439
440 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
441 {
James Feist0cd014a2019-04-08 15:04:33 -0700442 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700443 }
444
James Feist0cd014a2019-04-08 15:04:33 -0700445 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700446 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700447 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700448 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700449 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800450 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700451
James Feist0cd014a2019-04-08 15:04:33 -0700452 uint8_t thresholds = 0;
453
454 auto warningObject =
455 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
456 if (warningObject != sensorMap.end())
457 {
458 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
459 auto alarmLow = warningObject->second.find("WarningAlarmLow");
460 if (alarmHigh != warningObject->second.end())
461 {
462 if (std::get<bool>(alarmHigh->second))
463 {
464 thresholds |= static_cast<uint8_t>(
465 IPMISensorReadingByte3::upperNonCritical);
466 }
467 }
468 if (alarmLow != warningObject->second.end())
469 {
470 if (std::get<bool>(alarmLow->second))
471 {
472 thresholds |= static_cast<uint8_t>(
473 IPMISensorReadingByte3::lowerNonCritical);
474 }
475 }
476 }
477
478 auto criticalObject =
479 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
480 if (criticalObject != sensorMap.end())
481 {
482 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
483 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
484 if (alarmHigh != criticalObject->second.end())
485 {
486 if (std::get<bool>(alarmHigh->second))
487 {
488 thresholds |=
489 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
490 }
491 }
492 if (alarmLow != criticalObject->second.end())
493 {
494 if (std::get<bool>(alarmLow->second))
495 {
496 thresholds |=
497 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
498 }
499 }
500 }
501
502 // no discrete as of today so optional byte is never returned
503 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700504}
505
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000506/** @brief implements the Set Sensor threshold command
507 * @param sensorNumber - sensor number
508 * @param lowerNonCriticalThreshMask
509 * @param lowerCriticalThreshMask
510 * @param lowerNonRecovThreshMask
511 * @param upperNonCriticalThreshMask
512 * @param upperCriticalThreshMask
513 * @param upperNonRecovThreshMask
514 * @param reserved
515 * @param lowerNonCritical - lower non-critical threshold
516 * @param lowerCritical - Lower critical threshold
517 * @param lowerNonRecoverable - Lower non recovarable threshold
518 * @param upperNonCritical - Upper non-critical threshold
519 * @param upperCritical - Upper critical
520 * @param upperNonRecoverable - Upper Non-recoverable
521 *
522 * @returns IPMI completion code
523 */
524ipmi::RspType<> ipmiSenSetSensorThresholds(
525 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
526 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
527 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
528 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
529 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
530 uint8_t upperNonCritical, uint8_t upperCritical,
531 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700532{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000533 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700534
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000535 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700536 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000537 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700538 }
539
540 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000541 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700542 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000543 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700544 }
545
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000546 // if none of the threshold mask are set, nothing to do
547 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
548 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
549 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700550 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000551 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700552 }
553
554 std::string connection;
555 std::string path;
556
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000557 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700558 if (status)
559 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000560 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700561 }
562 SensorMap sensorMap;
563 if (!getSensorMap(connection, path, sensorMap))
564 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000565 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700566 }
567
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700568 double max = 0;
569 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700570 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700571
572 int16_t mValue = 0;
573 int16_t bValue = 0;
574 int8_t rExp = 0;
575 int8_t bExp = 0;
576 bool bSigned = false;
577
578 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
579 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000580 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700581 }
582
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700583 // store a vector of property name, value to set, and interface
584 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
585
586 // define the indexes of the tuple
587 constexpr uint8_t propertyName = 0;
588 constexpr uint8_t thresholdValue = 1;
589 constexpr uint8_t interface = 2;
590 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000591 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700592 {
593 auto findThreshold =
594 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
595 if (findThreshold == sensorMap.end())
596 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000597 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700598 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000599 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700600 {
601 auto findLower = findThreshold->second.find("CriticalLow");
602 if (findLower == findThreshold->second.end())
603 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000604 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700605 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000606 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700607 findThreshold->first);
608 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000609 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700610 {
611 auto findUpper = findThreshold->second.find("CriticalHigh");
612 if (findUpper == findThreshold->second.end())
613 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000614 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700615 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000616 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700617 findThreshold->first);
618 }
619 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000620 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700621 {
622 auto findThreshold =
623 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
624 if (findThreshold == sensorMap.end())
625 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000626 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700627 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000628 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700629 {
630 auto findLower = findThreshold->second.find("WarningLow");
631 if (findLower == findThreshold->second.end())
632 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000633 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700634 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000635 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700636 findThreshold->first);
637 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000638 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700639 {
640 auto findUpper = findThreshold->second.find("WarningHigh");
641 if (findUpper == findThreshold->second.end())
642 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000643 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000645 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700646 findThreshold->first);
647 }
648 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700649 for (const auto &property : thresholdsToSet)
650 {
651 // from section 36.3 in the IPMI Spec, assume all linear
652 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
653 (bValue * std::pow(10, bExp))) *
654 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700655 setDbusProperty(
656 *getSdBus(), connection, path, std::get<interface>(property),
657 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700658 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000659 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700660}
661
James Feist902c4c52019-04-16 14:51:31 -0700662IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700663{
James Feist902c4c52019-04-16 14:51:31 -0700664 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700665 auto warningInterface =
666 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
667 auto criticalInterface =
668 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
669
670 if ((warningInterface != sensorMap.end()) ||
671 (criticalInterface != sensorMap.end()))
672 {
673 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
674
675 if (sensorPair == sensorMap.end())
676 {
677 // should not have been able to find a sensor not implementing
678 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700679 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700680 }
681
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800682 double max = 0;
683 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700684 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700685
686 int16_t mValue = 0;
687 int16_t bValue = 0;
688 int8_t rExp = 0;
689 int8_t bExp = 0;
690 bool bSigned = false;
691
692 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
693 {
James Feist902c4c52019-04-16 14:51:31 -0700694 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700695 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700696 if (warningInterface != sensorMap.end())
697 {
698 auto &warningMap = warningInterface->second;
699
700 auto warningHigh = warningMap.find("WarningHigh");
701 auto warningLow = warningMap.find("WarningLow");
702
703 if (warningHigh != warningMap.end())
704 {
James Feist902c4c52019-04-16 14:51:31 -0700705
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700706 double value =
707 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700708 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700709 value, mValue, rExp, bValue, bExp, bSigned);
710 }
711 if (warningLow != warningMap.end())
712 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700713 double value =
714 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700715 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700716 value, mValue, rExp, bValue, bExp, bSigned);
717 }
718 }
719 if (criticalInterface != sensorMap.end())
720 {
721 auto &criticalMap = criticalInterface->second;
722
723 auto criticalHigh = criticalMap.find("CriticalHigh");
724 auto criticalLow = criticalMap.find("CriticalLow");
725
726 if (criticalHigh != criticalMap.end())
727 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700728 double value =
729 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700730 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700731 value, mValue, rExp, bValue, bExp, bSigned);
732 }
733 if (criticalLow != criticalMap.end())
734 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700735 double value =
736 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700737 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700738 value, mValue, rExp, bValue, bExp, bSigned);
739 }
740 }
741 }
James Feist902c4c52019-04-16 14:51:31 -0700742 return resp;
743}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700744
James Feist902c4c52019-04-16 14:51:31 -0700745ipmi::RspType<uint8_t, // readable
746 uint8_t, // lowerNCrit
747 uint8_t, // lowerCrit
748 uint8_t, // lowerNrecoverable
749 uint8_t, // upperNC
750 uint8_t, // upperCrit
751 uint8_t> // upperNRecoverable
752 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
753{
754 std::string connection;
755 std::string path;
756
757 auto status = getSensorConnection(sensorNumber, connection, path);
758 if (status)
759 {
760 return ipmi::response(status);
761 }
762
763 SensorMap sensorMap;
764 if (!getSensorMap(connection, path, sensorMap))
765 {
766 return ipmi::responseResponseError();
767 }
768
769 IPMIThresholds thresholdData;
770 try
771 {
772 thresholdData = getIPMIThresholds(sensorMap);
773 }
774 catch (std::exception &)
775 {
776 return ipmi::responseResponseError();
777 }
778
779 uint8_t readable = 0;
780 uint8_t lowerNC = 0;
781 uint8_t lowerCritical = 0;
782 uint8_t lowerNonRecoverable = 0;
783 uint8_t upperNC = 0;
784 uint8_t upperCritical = 0;
785 uint8_t upperNonRecoverable = 0;
786
787 if (thresholdData.warningHigh)
788 {
789 readable |=
790 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
791 upperNC = *thresholdData.warningHigh;
792 }
793 if (thresholdData.warningLow)
794 {
795 readable |=
796 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
797 lowerNC = *thresholdData.warningLow;
798 }
799
800 if (thresholdData.criticalHigh)
801 {
802 readable |=
803 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
804 upperCritical = *thresholdData.criticalHigh;
805 }
806 if (thresholdData.criticalLow)
807 {
808 readable |=
809 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
810 lowerCritical = *thresholdData.criticalLow;
811 }
812
813 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
814 lowerNonRecoverable, upperNC, upperCritical,
815 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700816}
817
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000818/** @brief implements the get Sensor event enable command
819 * @param sensorNumber - sensor number
820 *
821 * @returns IPMI completion code plus response data
822 * - enabled - Sensor Event messages
823 * - assertionEnabledLsb - Assertion event messages
824 * - assertionEnabledMsb - Assertion event messages
825 * - deassertionEnabledLsb - Deassertion event messages
826 * - deassertionEnabledMsb - Deassertion event messages
827 */
828
829ipmi::RspType<uint8_t, // enabled
830 uint8_t, // assertionEnabledLsb
831 uint8_t, // assertionEnabledMsb
832 uint8_t, // deassertionEnabledLsb
833 uint8_t> // deassertionEnabledMsb
834 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700835{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700836 std::string connection;
837 std::string path;
838
Patrick Venturea41714c2019-09-25 16:59:41 -0700839 uint8_t enabled = 0;
840 uint8_t assertionEnabledLsb = 0;
841 uint8_t assertionEnabledMsb = 0;
842 uint8_t deassertionEnabledLsb = 0;
843 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000844
845 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700846 if (status)
847 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000848 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700849 }
850
851 SensorMap sensorMap;
852 if (!getSensorMap(connection, path, sensorMap))
853 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000854 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700855 }
856
857 auto warningInterface =
858 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
859 auto criticalInterface =
860 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700861 if ((warningInterface != sensorMap.end()) ||
862 (criticalInterface != sensorMap.end()))
863 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000864 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700865 IPMISensorEventEnableByte2::sensorScanningEnable);
866 if (warningInterface != sensorMap.end())
867 {
868 auto &warningMap = warningInterface->second;
869
870 auto warningHigh = warningMap.find("WarningHigh");
871 auto warningLow = warningMap.find("WarningLow");
872 if (warningHigh != warningMap.end())
873 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000874 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700875 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000876 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700877 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
878 }
879 if (warningLow != warningMap.end())
880 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000881 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700882 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000883 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700884 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
885 }
886 }
887 if (criticalInterface != sensorMap.end())
888 {
889 auto &criticalMap = criticalInterface->second;
890
891 auto criticalHigh = criticalMap.find("CriticalHigh");
892 auto criticalLow = criticalMap.find("CriticalLow");
893
894 if (criticalHigh != criticalMap.end())
895 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000896 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700897 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000898 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700899 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
900 }
901 if (criticalLow != criticalMap.end())
902 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000903 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700904 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000905 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700906 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
907 }
908 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700909 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000910
911 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
912 assertionEnabledMsb, deassertionEnabledLsb,
913 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700914}
915
916ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
917 ipmi_request_t request,
918 ipmi_response_t response,
919 ipmi_data_len_t dataLen,
920 ipmi_context_t context)
921{
922 if (*dataLen != 1)
923 {
924 *dataLen = 0;
925 return IPMI_CC_REQ_DATA_LEN_INVALID;
926 }
927 *dataLen = 0; // default to 0 in case of an error
928
929 uint8_t sensnum = *(static_cast<uint8_t *>(request));
930
931 std::string connection;
932 std::string path;
933
934 auto status = getSensorConnection(sensnum, connection, path);
935 if (status)
936 {
937 return status;
938 }
939
940 SensorMap sensorMap;
941 if (!getSensorMap(connection, path, sensorMap))
942 {
943 return IPMI_CC_RESPONSE_ERROR;
944 }
945
946 auto warningInterface =
947 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
948 auto criticalInterface =
949 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
950
951 // zero out response buff
952 auto responseClear = static_cast<uint8_t *>(response);
953 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
954 auto resp = static_cast<SensorEventStatusResp *>(response);
955 resp->enabled =
956 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
957
James Feist392786a2019-03-19 13:36:10 -0700958 std::optional<bool> criticalDeassertHigh =
959 thresholdDeassertMap[path]["CriticalAlarmHigh"];
960 std::optional<bool> criticalDeassertLow =
961 thresholdDeassertMap[path]["CriticalAlarmLow"];
962 std::optional<bool> warningDeassertHigh =
963 thresholdDeassertMap[path]["WarningAlarmHigh"];
964 std::optional<bool> warningDeassertLow =
965 thresholdDeassertMap[path]["WarningAlarmLow"];
966
967 if (criticalDeassertHigh && !*criticalDeassertHigh)
968 {
969 resp->deassertionsMSB |= static_cast<uint8_t>(
970 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
971 }
972 if (criticalDeassertLow && !*criticalDeassertLow)
973 {
974 resp->deassertionsMSB |= static_cast<uint8_t>(
975 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
976 }
977 if (warningDeassertHigh && !*warningDeassertHigh)
978 {
979 resp->deassertionsLSB |= static_cast<uint8_t>(
980 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
981 }
982 if (warningDeassertLow && !*warningDeassertLow)
983 {
984 resp->deassertionsLSB |= static_cast<uint8_t>(
985 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
986 }
987
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700988 if ((warningInterface != sensorMap.end()) ||
989 (criticalInterface != sensorMap.end()))
990 {
991 resp->enabled = static_cast<uint8_t>(
992 IPMISensorEventEnableByte2::eventMessagesEnable);
993 if (warningInterface != sensorMap.end())
994 {
995 auto &warningMap = warningInterface->second;
996
997 auto warningHigh = warningMap.find("WarningAlarmHigh");
998 auto warningLow = warningMap.find("WarningAlarmLow");
999 auto warningHighAlarm = false;
1000 auto warningLowAlarm = false;
1001
1002 if (warningHigh != warningMap.end())
1003 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001004 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001005 }
1006 if (warningLow != warningMap.end())
1007 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001008 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001009 }
1010 if (warningHighAlarm)
1011 {
1012 resp->assertionsLSB |= static_cast<uint8_t>(
1013 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1014 }
1015 if (warningLowAlarm)
1016 {
1017 resp->assertionsLSB |= 1; // lower nc going low
1018 }
1019 }
1020 if (criticalInterface != sensorMap.end())
1021 {
1022 auto &criticalMap = criticalInterface->second;
1023
1024 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1025 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1026 auto criticalHighAlarm = false;
1027 auto criticalLowAlarm = false;
1028
1029 if (criticalHigh != criticalMap.end())
1030 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001031 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001032 }
1033 if (criticalLow != criticalMap.end())
1034 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001035 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001036 }
1037 if (criticalHighAlarm)
1038 {
1039 resp->assertionsMSB |= static_cast<uint8_t>(
1040 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1041 }
1042 if (criticalLowAlarm)
1043 {
1044 resp->assertionsLSB |= static_cast<uint8_t>(
1045 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1046 }
1047 }
1048 *dataLen = sizeof(SensorEventStatusResp);
1049 }
1050
1051 // no thresholds enabled, don't need assertionMSB
1052 else
1053 {
1054 *dataLen = sizeof(SensorEventStatusResp) - 1;
1055 }
1056
1057 return IPMI_CC_OK;
1058}
1059
1060/* end sensor commands */
1061
1062/* storage commands */
1063
James Feist74c50c62019-08-14 14:18:41 -07001064ipmi::RspType<uint8_t, // sdr version
1065 uint16_t, // record count
1066 uint16_t, // free space
1067 uint32_t, // most recent addition
1068 uint32_t, // most recent erase
1069 uint8_t // operationSupport
1070 >
1071 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001072{
James Feist74c50c62019-08-14 14:18:41 -07001073 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001074 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1075 {
James Feist74c50c62019-08-14 14:18:41 -07001076 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001077 }
1078
James Feist74c50c62019-08-14 14:18:41 -07001079 size_t fruCount = 0;
1080 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1081 if (ret != ipmi::ccSuccess)
1082 {
1083 return ipmi::response(ret);
1084 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001085
James Feist74c50c62019-08-14 14:18:41 -07001086 uint16_t recordCount =
1087 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001088
James Feist74c50c62019-08-14 14:18:41 -07001089 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001090 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001091
1092 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001093 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001094 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001095 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001096 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1097 unspecifiedFreeSpace, sdrLastAdd,
1098 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001099}
1100
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001101/** @brief implements the get SDR allocation info command
1102 *
1103 * @returns IPMI completion code plus response data
1104 * - allocUnits - Number of possible allocation units
1105 * - allocUnitSize - Allocation unit size in bytes.
1106 * - allocUnitFree - Number of free allocation units
1107 * - allocUnitLargestFree - Largest free block in allocation units
1108 * - maxRecordSize - Maximum record size in allocation units.
1109 */
1110ipmi::RspType<uint16_t, // allocUnits
1111 uint16_t, // allocUnitSize
1112 uint16_t, // allocUnitFree
1113 uint16_t, // allocUnitLargestFree
1114 uint8_t // maxRecordSize
1115 >
1116 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001117{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001119 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001121 constexpr uint16_t allocUnitFree = 0;
1122 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001123 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001124 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001125
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001126 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1127 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001128}
1129
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001130/** @brief implements the reserve SDR command
1131 * @returns IPMI completion code plus response data
1132 * - sdrReservationID
1133 */
1134ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001135{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001136 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001137 if (sdrReservationID == 0)
1138 {
1139 sdrReservationID++;
1140 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001141
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001142 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001143}
1144
James Feistb49a98a2019-04-16 13:48:09 -07001145ipmi::RspType<uint16_t, // next record ID
1146 std::vector<uint8_t> // payload
1147 >
1148 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1149 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001150{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001151 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001152
1153 // reservation required for partial reads with non zero offset into
1154 // record
James Feistb49a98a2019-04-16 13:48:09 -07001155 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001156 {
James Feistb49a98a2019-04-16 13:48:09 -07001157 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001158 }
1159
1160 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1161 {
James Feistb49a98a2019-04-16 13:48:09 -07001162 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001163 }
1164
1165 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001166 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1167 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001168 {
James Feistb49a98a2019-04-16 13:48:09 -07001169 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001170 }
1171
James Feist74c50c62019-08-14 14:18:41 -07001172 size_t lastRecord =
1173 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001174 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001175 {
James Feistb49a98a2019-04-16 13:48:09 -07001176 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001177 }
James Feistb49a98a2019-04-16 13:48:09 -07001178 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001179 {
James Feistb49a98a2019-04-16 13:48:09 -07001180 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001181 }
1182
James Feistb49a98a2019-04-16 13:48:09 -07001183 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001184
James Feistb49a98a2019-04-16 13:48:09 -07001185 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001186 {
James Feist74c50c62019-08-14 14:18:41 -07001187 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001188 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001189 if (fruIndex >= fruCount)
1190 {
James Feist74c50c62019-08-14 14:18:41 -07001191 // handle type 12 hardcoded records
1192 size_t type12Index = fruIndex - fruCount;
1193 if (type12Index >= ipmi::storage::type12Count ||
1194 offset > sizeof(Type12Record))
1195 {
1196 return ipmi::responseInvalidFieldRequest();
1197 }
1198 std::vector<uint8_t> record =
1199 ipmi::storage::getType12SDRs(type12Index, recordID);
1200 if (record.size() < (offset + bytesToRead))
1201 {
1202 bytesToRead = record.size() - offset;
1203 }
James Feistb49a98a2019-04-16 13:48:09 -07001204
James Feist74c50c62019-08-14 14:18:41 -07001205 recordData.insert(recordData.end(), record.begin() + offset,
1206 record.begin() + offset + bytesToRead);
1207 }
1208 else
1209 {
1210 // handle fru records
1211 get_sdr::SensorDataFruRecord data;
1212 if (offset > sizeof(data))
1213 {
1214 return ipmi::responseInvalidFieldRequest();
1215 }
1216 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1217 if (ret != IPMI_CC_OK)
1218 {
1219 return ipmi::response(ret);
1220 }
1221 data.header.record_id_msb = recordID << 8;
1222 data.header.record_id_lsb = recordID & 0xFF;
1223 if (sizeof(data) < (offset + bytesToRead))
1224 {
1225 bytesToRead = sizeof(data) - offset;
1226 }
1227
1228 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1229 recordData.insert(recordData.end(), respStart,
1230 respStart + bytesToRead);
1231 }
James Feistb49a98a2019-04-16 13:48:09 -07001232
1233 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001234 }
1235
1236 std::string connection;
1237 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001238 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001239 for (const auto &sensor : sensorTree)
1240 {
1241 if (sensorIndex-- == 0)
1242 {
1243 if (!sensor.second.size())
1244 {
James Feistb49a98a2019-04-16 13:48:09 -07001245 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001246 }
1247 connection = sensor.second.begin()->first;
1248 path = sensor.first;
1249 break;
1250 }
1251 }
1252
1253 SensorMap sensorMap;
1254 if (!getSensorMap(connection, path, sensorMap))
1255 {
James Feistb49a98a2019-04-16 13:48:09 -07001256 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001257 }
James Feistb49a98a2019-04-16 13:48:09 -07001258 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001259 get_sdr::SensorDataFullRecord record = {0};
1260
James Feistb49a98a2019-04-16 13:48:09 -07001261 record.header.record_id_msb = recordID << 8;
1262 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001263 record.header.sdr_version = ipmiSdrVersion;
1264 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1265 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1266 sizeof(get_sdr::SensorDataRecordHeader);
1267 record.key.owner_id = 0x20;
1268 record.key.owner_lun = 0x0;
1269 record.key.sensor_number = sensornumber;
1270
1271 record.body.entity_id = 0x0;
1272 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001273 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001274 record.body.sensor_type = getSensorTypeFromPath(path);
1275 std::string type = getSensorTypeStringFromPath(path);
1276 auto typeCstr = type.c_str();
1277 auto findUnits = sensorUnits.find(typeCstr);
1278 if (findUnits != sensorUnits.end())
1279 {
1280 record.body.sensor_units_2_base =
1281 static_cast<uint8_t>(findUnits->second);
1282 } // else default 0x0 unspecified
1283
1284 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1285
1286 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1287 if (sensorObject == sensorMap.end())
1288 {
James Feistb49a98a2019-04-16 13:48:09 -07001289 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001290 }
1291
1292 auto maxObject = sensorObject->second.find("MaxValue");
1293 auto minObject = sensorObject->second.find("MinValue");
1294 double max = 128;
1295 double min = -127;
1296 if (maxObject != sensorObject->second.end())
1297 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001298 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001299 }
1300
1301 if (minObject != sensorObject->second.end())
1302 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001303 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001304 }
1305
Yong Li1f2eb5e2019-05-23 14:07:17 +08001306 int16_t mValue = 0;
1307 int8_t rExp = 0;
1308 int16_t bValue = 0;
1309 int8_t bExp = 0;
1310 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001311
1312 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1313 {
James Feistb49a98a2019-04-16 13:48:09 -07001314 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001315 }
1316
1317 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1318 record.body.m_lsb = mValue & 0xFF;
1319
1320 // move the smallest bit of the MSB into place (bit 9)
1321 // the MSbs are bits 7:8 in m_msb_and_tolerance
1322 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1323
1324 // assign the negative
1325 if (mValue < 0)
1326 {
1327 mMsb |= (1 << 7);
1328 }
1329 record.body.m_msb_and_tolerance = mMsb;
1330
1331 record.body.b_lsb = bValue & 0xFF;
1332
1333 // move the smallest bit of the MSB into place
1334 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1335 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1336
1337 // assign the negative
1338 if (bValue < 0)
1339 {
1340 bMsb |= (1 << 7);
1341 }
1342 record.body.b_msb_and_accuracy_lsb = bMsb;
1343
1344 record.body.r_b_exponents = bExp & 0x7;
1345 if (bExp < 0)
1346 {
1347 record.body.r_b_exponents |= 1 << 3;
1348 }
1349 record.body.r_b_exponents = (rExp & 0x7) << 4;
1350 if (rExp < 0)
1351 {
1352 record.body.r_b_exponents |= 1 << 7;
1353 }
1354
1355 // todo fill out rest of units
1356 if (bSigned)
1357 {
1358 record.body.sensor_units_1 = 1 << 7;
1359 }
1360
1361 // populate sensor name from path
1362 std::string name;
1363 size_t nameStart = path.rfind("/");
1364 if (nameStart != std::string::npos)
1365 {
1366 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1367 }
1368
1369 std::replace(name.begin(), name.end(), '_', ' ');
1370 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1371 {
James Feist979a2322019-05-15 09:06:54 -07001372 // try to not truncate by replacing common words
1373 constexpr std::array<std::pair<const char *, const char *>, 2>
1374 replaceWords = {std::make_pair("Output", "Out"),
1375 std::make_pair("Input", "In")};
1376 for (const auto &[find, replace] : replaceWords)
1377 {
1378 boost::replace_all(name, find, replace);
1379 }
1380
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001381 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1382 }
1383 record.body.id_string_info = name.size();
1384 std::strncpy(record.body.id_string, name.c_str(),
1385 sizeof(record.body.id_string));
1386
James Feistc4b15bc2019-04-16 15:41:39 -07001387 IPMIThresholds thresholdData;
1388 try
1389 {
1390 thresholdData = getIPMIThresholds(sensorMap);
1391 }
1392 catch (std::exception &)
1393 {
1394 return ipmi::responseResponseError();
1395 }
1396
1397 if (thresholdData.criticalHigh)
1398 {
1399 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1400 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1401 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1402 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1403 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1404 record.body.discrete_reading_setting_mask[0] |=
1405 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1406 }
1407 if (thresholdData.warningHigh)
1408 {
1409 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1410 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1411 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1412 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1413 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1414 record.body.discrete_reading_setting_mask[0] |=
1415 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1416 }
1417 if (thresholdData.criticalLow)
1418 {
1419 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1420 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1421 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1422 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1423 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1424 record.body.discrete_reading_setting_mask[0] |=
1425 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1426 }
1427 if (thresholdData.warningLow)
1428 {
1429 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1430 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1431 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1432 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1433 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1434 record.body.discrete_reading_setting_mask[0] |=
1435 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1436 }
1437
1438 // everything that is readable is setable
1439 record.body.discrete_reading_setting_mask[1] =
1440 record.body.discrete_reading_setting_mask[0];
1441
James Feistb49a98a2019-04-16 13:48:09 -07001442 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001443 {
James Feistb49a98a2019-04-16 13:48:09 -07001444 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001445 }
1446
James Feistb49a98a2019-04-16 13:48:09 -07001447 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1448 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001449
James Feistb49a98a2019-04-16 13:48:09 -07001450 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001451}
1452/* end storage commands */
1453
1454void registerSensorFunctions()
1455{
1456 // get firmware version information
1457 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1458 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1459
1460 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001461 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1462 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001463
1464 // <Set Sensor Reading and Event Status>
1465 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001466 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001467 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1468
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001469 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001470 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1471 ipmi::sensor_event::cmdPlatformEvent,
1472 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001473
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001474 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001475 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1476 ipmi::sensor_event::cmdGetSensorReading,
1477 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001478
1479 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001480 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1481 ipmi::sensor_event::cmdGetSensorThreshold,
1482 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001483
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001484 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001485 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1486 ipmi::sensor_event::cmdSetSensorThreshold,
1487 ipmi::Privilege::Operator,
1488 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001489
1490 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001491 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1492 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001493 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001494
1495 // <Get Sensor Event Status>
1496 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001497 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1498 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001499
1500 // register all storage commands for both Sensor and Storage command
1501 // versions
1502
1503 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001504 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1505 ipmi::storage::cmdGetSdrRepositoryInfo,
1506 ipmi::Privilege::User,
1507 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001508
1509 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001510 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1511 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1512 ipmi::Privilege::User,
1513 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001514
1515 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001516 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1517 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001518 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001519
Vernon Mauery98bbf692019-09-16 11:14:59 -07001520 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1521 ipmi::storage::cmdReserveSdrRepository,
1522 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001523
1524 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001525 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1526 ipmi::sensor_event::cmdGetDeviceSdr,
1527 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001528
Vernon Mauery98bbf692019-09-16 11:14:59 -07001529 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1530 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1531 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001532}
1533} // namespace ipmi