blob: 8277bf21dc06b11d252e8799d76a56decb25122c [file] [log] [blame]
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001/*
2// Copyright (c) 2017 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Patrick Venture31b35d52019-10-20 13:25:16 -070017#include "sensorcommands.hpp"
18
19#include "commandutils.hpp"
20#include "ipmi_to_redfish_hooks.hpp"
21#include "sdrutils.hpp"
22#include "sensorutils.hpp"
23#include "storagecommands.hpp"
24
Patrick Venturef777e1b2019-09-25 17:45:44 -070025#include <algorithm>
Patrick Venture44ec88e2019-09-25 17:48:29 -070026#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070027#include <boost/algorithm/string.hpp>
28#include <boost/container/flat_map.hpp>
29#include <chrono>
30#include <cmath>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070031#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070032#include <iostream>
James Feist2a265d52019-04-08 11:16:27 -070033#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070034#include <ipmid/utils.hpp>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070035#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070036#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070037#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070038#include <phosphor-logging/log.hpp>
39#include <sdbusplus/bus.hpp>
Patrick Venturee6154022019-09-25 17:50:25 -070040#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070041#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070042#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070043#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070044
45namespace ipmi
46{
47using ManagedObjectType =
48 std::map<sdbusplus::message::object_path,
49 std::map<std::string, std::map<std::string, DbusVariant>>>;
50
51using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
52
53static constexpr int sensorListUpdatePeriod = 10;
54static constexpr int sensorMapUpdatePeriod = 2;
55
56constexpr size_t maxSDRTotalSize =
57 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
58constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
59
60static uint16_t sdrReservationID;
61static uint32_t sdrLastAdd = noTimestamp;
62static uint32_t sdrLastRemove = noTimestamp;
63
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053064SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070065static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
66
Jason M. Bills17add592018-11-12 14:30:12 -080067// Specify the comparison required to sort and find char* map objects
68struct CmpStr
69{
70 bool operator()(const char *a, const char *b) const
71 {
72 return std::strcmp(a, b) < 0;
73 }
74};
75const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
76 sensorUnits{{{"temperature", SensorUnits::degreesC},
77 {"voltage", SensorUnits::volts},
78 {"current", SensorUnits::amps},
79 {"fan_tach", SensorUnits::rpm},
80 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070081
82void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070083
84static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070085 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070086 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
87 "sensors/'",
88 [](sdbusplus::message::message &m) {
89 sensorTree.clear();
90 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
91 std::chrono::system_clock::now().time_since_epoch())
92 .count();
93 });
94
95static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070096 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070097 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
98 "sensors/'",
99 [](sdbusplus::message::message &m) {
100 sensorTree.clear();
101 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
102 std::chrono::system_clock::now().time_since_epoch())
103 .count();
104 });
105
James Feist392786a2019-03-19 13:36:10 -0700106// this keeps track of deassertions for sensor event status command. A
107// deasertion can only happen if an assertion was seen first.
108static boost::container::flat_map<
109 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
110 thresholdDeassertMap;
111
112static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700113 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700114 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
115 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
116 [](sdbusplus::message::message &m) {
117 boost::container::flat_map<std::string, std::variant<bool, double>>
118 values;
119 m.read(std::string(), values);
120
121 auto findAssert =
122 std::find_if(values.begin(), values.end(), [](const auto &pair) {
123 return pair.first.find("Alarm") != std::string::npos;
124 });
125 if (findAssert != values.end())
126 {
127 auto ptr = std::get_if<bool>(&(findAssert->second));
128 if (ptr == nullptr)
129 {
130 phosphor::logging::log<phosphor::logging::level::ERR>(
131 "thresholdChanged: Assert non bool");
132 return;
133 }
134 if (*ptr)
135 {
136 phosphor::logging::log<phosphor::logging::level::INFO>(
137 "thresholdChanged: Assert",
138 phosphor::logging::entry("SENSOR=%s", m.get_path()));
139 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
140 }
141 else
142 {
143 auto &value =
144 thresholdDeassertMap[m.get_path()][findAssert->first];
145 if (value)
146 {
147 phosphor::logging::log<phosphor::logging::level::INFO>(
148 "thresholdChanged: deassert",
149 phosphor::logging::entry("SENSOR=%s", m.get_path()));
150 value = *ptr;
151 }
152 }
153 }
154 });
155
James Feistaecaef72019-04-26 10:30:32 -0700156static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
157 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700158{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700159 max = 127;
160 min = -128;
161
James Feistaecaef72019-04-26 10:30:32 -0700162 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
163 auto critical =
164 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
165 auto warning =
166 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
167
168 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700169 {
James Feistaecaef72019-04-26 10:30:32 -0700170 auto maxMap = sensorObject->second.find("MaxValue");
171 auto minMap = sensorObject->second.find("MinValue");
172
173 if (maxMap != sensorObject->second.end())
174 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700175 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700176 }
177 if (minMap != sensorObject->second.end())
178 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700179 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700180 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700181 }
James Feistaecaef72019-04-26 10:30:32 -0700182 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700183 {
James Feistaecaef72019-04-26 10:30:32 -0700184 auto lower = critical->second.find("CriticalLow");
185 auto upper = critical->second.find("CriticalHigh");
186 if (lower != critical->second.end())
187 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700188 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700189 min = std::min(value, min);
190 }
191 if (upper != critical->second.end())
192 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700193 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700194 max = std::max(value, max);
195 }
196 }
197 if (warning != sensorMap.end())
198 {
199
200 auto lower = warning->second.find("WarningLow");
201 auto upper = warning->second.find("WarningHigh");
202 if (lower != warning->second.end())
203 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700204 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700205 min = std::min(value, min);
206 }
207 if (upper != warning->second.end())
208 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700209 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700210 max = std::max(value, max);
211 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700212 }
213}
214
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700215static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
216 SensorMap &sensorMap)
217{
218 static boost::container::flat_map<
219 std::string, std::chrono::time_point<std::chrono::steady_clock>>
220 updateTimeMap;
221
222 auto updateFind = updateTimeMap.find(sensorConnection);
223 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
224 if (updateFind != updateTimeMap.end())
225 {
226 lastUpdate = updateFind->second;
227 }
228
229 auto now = std::chrono::steady_clock::now();
230
231 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
232 .count() > sensorMapUpdatePeriod)
233 {
234 updateTimeMap[sensorConnection] = now;
235
Vernon Mauery15419dd2019-05-24 09:40:30 -0700236 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
237 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700238 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
239 "GetManagedObjects");
240
241 ManagedObjectType managedObjects;
242 try
243 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700244 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700245 reply.read(managedObjects);
246 }
247 catch (sdbusplus::exception_t &)
248 {
249 phosphor::logging::log<phosphor::logging::level::ERR>(
250 "Error getting managed objects from connection",
251 phosphor::logging::entry("CONNECTION=%s",
252 sensorConnection.c_str()));
253 return false;
254 }
255
256 SensorCache[sensorConnection] = managedObjects;
257 }
258 auto connection = SensorCache.find(sensorConnection);
259 if (connection == SensorCache.end())
260 {
261 return false;
262 }
263 auto path = connection->second.find(sensorPath);
264 if (path == connection->second.end())
265 {
266 return false;
267 }
268 sensorMap = path->second;
269
270 return true;
271}
272
273/* sensor commands */
274ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
275 ipmi_request_t request,
276 ipmi_response_t response,
277 ipmi_data_len_t dataLen,
278 ipmi_context_t context)
279{
280 *dataLen = 0;
281 printCommand(+netfn, +cmd);
282 return IPMI_CC_INVALID;
283}
284
James Feist7aaf3fe2019-06-25 11:52:11 -0700285namespace meHealth
286{
287constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
288constexpr const char *path = "/xyz/openbmc_project/status/me";
289constexpr const char *interface = "xyz.openbmc_project.SetHealth";
290constexpr const char *method = "SetHealth";
291constexpr const char *critical = "critical";
292constexpr const char *warning = "warning";
293constexpr const char *ok = "ok";
294} // namespace meHealth
295
296static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
297{
298 constexpr const std::array<uint8_t, 10> critical = {
299 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
300 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
301 0x1A};
302
303 std::string state;
304 if (std::find(critical.begin(), critical.end(), eventData2) !=
305 critical.end())
306 {
307 state = meHealth::critical;
308 }
309 // special case 0x3 as we only care about a few states
310 else if (eventData2 == 0x3)
311 {
312 if (eventData3 <= 0x2)
313 {
314 state = meHealth::warning;
315 }
316 else
317 {
318 return;
319 }
320 }
321 else if (std::find(warning.begin(), warning.end(), eventData2) !=
322 warning.end())
323 {
324 state = meHealth::warning;
325 }
326 else
327 {
328 return;
329 }
330 if (disable)
331 {
332 state = meHealth::ok;
333 }
334
335 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
336 auto setHealth =
337 dbus->new_method_call(meHealth::busname, meHealth::path,
338 meHealth::interface, meHealth::method);
339 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
340 try
341 {
342 dbus->call(setHealth);
343 }
344 catch (sdbusplus::exception_t &)
345 {
346 phosphor::logging::log<phosphor::logging::level::ERR>(
347 "Failed to set ME Health");
348 }
349}
350
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700351ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
352{
James Feist7aaf3fe2019-06-25 11:52:11 -0700353 constexpr const uint8_t meId = 0x2C;
354 constexpr const uint8_t meSensorNum = 0x17;
355 constexpr const uint8_t disabled = 0x80;
356
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700357 uint8_t generatorID = 0;
358 uint8_t evmRev = 0;
359 uint8_t sensorType = 0;
360 uint8_t sensorNum = 0;
361 uint8_t eventType = 0;
362 uint8_t eventData1 = 0;
363 std::optional<uint8_t> eventData2 = 0;
364 std::optional<uint8_t> eventData3 = 0;
365
366 // todo: This check is supposed to be based on the incoming channel.
367 // e.g. system channel will provide upto 8 bytes including generator
368 // ID, but ipmb channel will provide only up to 7 bytes without the
369 // generator ID.
370 // Support for this check is coming in future patches, so for now just base
371 // it on if the first byte is the EvMRev (0x04).
372 if (p.size() && p.data()[0] == 0x04)
373 {
374 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
375 eventData2, eventData3);
376 // todo: the generator ID for this channel is supposed to come from the
377 // IPMB requesters slave address. Support for this is coming in future
378 // patches, so for now just assume it is coming from the ME (0x2C).
379 generatorID = 0x2C;
380 }
381 else
382 {
383 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
384 eventData1, eventData2, eventData3);
385 }
386 if (!p.fullyUnpacked())
387 {
388 return ipmi::responseReqDataLenInvalid();
389 }
390
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700391 // Send this request to the Redfish hooks to log it as a Redfish message
392 // instead. There is no need to add it to the SEL, so just return success.
393 intel_oem::ipmi::sel::checkRedfishHooks(
394 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
395 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700396
James Feist7aaf3fe2019-06-25 11:52:11 -0700397 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
398 eventData3)
399 {
400 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
401 }
402
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700403 return ipmi::responseSuccess();
404}
405
James Feist0cd014a2019-04-08 15:04:33 -0700406ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
407 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700408{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700409 std::string connection;
410 std::string path;
411
412 auto status = getSensorConnection(sensnum, connection, path);
413 if (status)
414 {
James Feist0cd014a2019-04-08 15:04:33 -0700415 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700416 }
417
418 SensorMap sensorMap;
419 if (!getSensorMap(connection, path, sensorMap))
420 {
James Feist0cd014a2019-04-08 15:04:33 -0700421 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700422 }
423 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
424
425 if (sensorObject == sensorMap.end() ||
426 sensorObject->second.find("Value") == sensorObject->second.end())
427 {
James Feist0cd014a2019-04-08 15:04:33 -0700428 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700429 }
James Feist0cd014a2019-04-08 15:04:33 -0700430 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700431 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700432
Yong Li1f2eb5e2019-05-23 14:07:17 +0800433 double max = 0;
434 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700435 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700436
437 int16_t mValue = 0;
438 int16_t bValue = 0;
439 int8_t rExp = 0;
440 int8_t bExp = 0;
441 bool bSigned = false;
442
443 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
444 {
James Feist0cd014a2019-04-08 15:04:33 -0700445 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700446 }
447
James Feist0cd014a2019-04-08 15:04:33 -0700448 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700449 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700450 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700451 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700452 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800453 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700454
James Feist0cd014a2019-04-08 15:04:33 -0700455 uint8_t thresholds = 0;
456
457 auto warningObject =
458 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
459 if (warningObject != sensorMap.end())
460 {
461 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
462 auto alarmLow = warningObject->second.find("WarningAlarmLow");
463 if (alarmHigh != warningObject->second.end())
464 {
465 if (std::get<bool>(alarmHigh->second))
466 {
467 thresholds |= static_cast<uint8_t>(
468 IPMISensorReadingByte3::upperNonCritical);
469 }
470 }
471 if (alarmLow != warningObject->second.end())
472 {
473 if (std::get<bool>(alarmLow->second))
474 {
475 thresholds |= static_cast<uint8_t>(
476 IPMISensorReadingByte3::lowerNonCritical);
477 }
478 }
479 }
480
481 auto criticalObject =
482 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
483 if (criticalObject != sensorMap.end())
484 {
485 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
486 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
487 if (alarmHigh != criticalObject->second.end())
488 {
489 if (std::get<bool>(alarmHigh->second))
490 {
491 thresholds |=
492 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
493 }
494 }
495 if (alarmLow != criticalObject->second.end())
496 {
497 if (std::get<bool>(alarmLow->second))
498 {
499 thresholds |=
500 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
501 }
502 }
503 }
504
505 // no discrete as of today so optional byte is never returned
506 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700507}
508
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000509/** @brief implements the Set Sensor threshold command
510 * @param sensorNumber - sensor number
511 * @param lowerNonCriticalThreshMask
512 * @param lowerCriticalThreshMask
513 * @param lowerNonRecovThreshMask
514 * @param upperNonCriticalThreshMask
515 * @param upperCriticalThreshMask
516 * @param upperNonRecovThreshMask
517 * @param reserved
518 * @param lowerNonCritical - lower non-critical threshold
519 * @param lowerCritical - Lower critical threshold
520 * @param lowerNonRecoverable - Lower non recovarable threshold
521 * @param upperNonCritical - Upper non-critical threshold
522 * @param upperCritical - Upper critical
523 * @param upperNonRecoverable - Upper Non-recoverable
524 *
525 * @returns IPMI completion code
526 */
527ipmi::RspType<> ipmiSenSetSensorThresholds(
528 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
529 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
530 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
531 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
532 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
533 uint8_t upperNonCritical, uint8_t upperCritical,
534 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700535{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000536 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700537
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000538 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700539 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000540 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700541 }
542
543 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000544 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700545 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000546 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700547 }
548
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000549 // if none of the threshold mask are set, nothing to do
550 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
551 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
552 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700553 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000554 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700555 }
556
557 std::string connection;
558 std::string path;
559
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000560 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700561 if (status)
562 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000563 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700564 }
565 SensorMap sensorMap;
566 if (!getSensorMap(connection, path, sensorMap))
567 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000568 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700569 }
570
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700571 double max = 0;
572 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700573 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700574
575 int16_t mValue = 0;
576 int16_t bValue = 0;
577 int8_t rExp = 0;
578 int8_t bExp = 0;
579 bool bSigned = false;
580
581 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
582 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000583 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700584 }
585
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700586 // store a vector of property name, value to set, and interface
587 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
588
589 // define the indexes of the tuple
590 constexpr uint8_t propertyName = 0;
591 constexpr uint8_t thresholdValue = 1;
592 constexpr uint8_t interface = 2;
593 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000594 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700595 {
596 auto findThreshold =
597 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
598 if (findThreshold == sensorMap.end())
599 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000600 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700601 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000602 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700603 {
604 auto findLower = findThreshold->second.find("CriticalLow");
605 if (findLower == findThreshold->second.end())
606 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000607 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700608 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000609 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700610 findThreshold->first);
611 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000612 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700613 {
614 auto findUpper = findThreshold->second.find("CriticalHigh");
615 if (findUpper == findThreshold->second.end())
616 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000617 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700618 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000619 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620 findThreshold->first);
621 }
622 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000623 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700624 {
625 auto findThreshold =
626 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
627 if (findThreshold == sensorMap.end())
628 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000629 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700630 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000631 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700632 {
633 auto findLower = findThreshold->second.find("WarningLow");
634 if (findLower == findThreshold->second.end())
635 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000636 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700637 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000638 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700639 findThreshold->first);
640 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000641 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700642 {
643 auto findUpper = findThreshold->second.find("WarningHigh");
644 if (findUpper == findThreshold->second.end())
645 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000646 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700647 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000648 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700649 findThreshold->first);
650 }
651 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700652 for (const auto &property : thresholdsToSet)
653 {
654 // from section 36.3 in the IPMI Spec, assume all linear
655 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
656 (bValue * std::pow(10, bExp))) *
657 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700658 setDbusProperty(
659 *getSdBus(), connection, path, std::get<interface>(property),
660 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700661 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000662 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700663}
664
James Feist902c4c52019-04-16 14:51:31 -0700665IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700666{
James Feist902c4c52019-04-16 14:51:31 -0700667 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700668 auto warningInterface =
669 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
670 auto criticalInterface =
671 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
672
673 if ((warningInterface != sensorMap.end()) ||
674 (criticalInterface != sensorMap.end()))
675 {
676 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
677
678 if (sensorPair == sensorMap.end())
679 {
680 // should not have been able to find a sensor not implementing
681 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700682 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700683 }
684
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800685 double max = 0;
686 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700687 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700688
689 int16_t mValue = 0;
690 int16_t bValue = 0;
691 int8_t rExp = 0;
692 int8_t bExp = 0;
693 bool bSigned = false;
694
695 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
696 {
James Feist902c4c52019-04-16 14:51:31 -0700697 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700698 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700699 if (warningInterface != sensorMap.end())
700 {
701 auto &warningMap = warningInterface->second;
702
703 auto warningHigh = warningMap.find("WarningHigh");
704 auto warningLow = warningMap.find("WarningLow");
705
706 if (warningHigh != warningMap.end())
707 {
James Feist902c4c52019-04-16 14:51:31 -0700708
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700709 double value =
710 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700711 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700712 value, mValue, rExp, bValue, bExp, bSigned);
713 }
714 if (warningLow != warningMap.end())
715 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700716 double value =
717 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700718 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700719 value, mValue, rExp, bValue, bExp, bSigned);
720 }
721 }
722 if (criticalInterface != sensorMap.end())
723 {
724 auto &criticalMap = criticalInterface->second;
725
726 auto criticalHigh = criticalMap.find("CriticalHigh");
727 auto criticalLow = criticalMap.find("CriticalLow");
728
729 if (criticalHigh != criticalMap.end())
730 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700731 double value =
732 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700733 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700734 value, mValue, rExp, bValue, bExp, bSigned);
735 }
736 if (criticalLow != criticalMap.end())
737 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700738 double value =
739 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700740 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700741 value, mValue, rExp, bValue, bExp, bSigned);
742 }
743 }
744 }
James Feist902c4c52019-04-16 14:51:31 -0700745 return resp;
746}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700747
James Feist902c4c52019-04-16 14:51:31 -0700748ipmi::RspType<uint8_t, // readable
749 uint8_t, // lowerNCrit
750 uint8_t, // lowerCrit
751 uint8_t, // lowerNrecoverable
752 uint8_t, // upperNC
753 uint8_t, // upperCrit
754 uint8_t> // upperNRecoverable
755 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
756{
757 std::string connection;
758 std::string path;
759
760 auto status = getSensorConnection(sensorNumber, connection, path);
761 if (status)
762 {
763 return ipmi::response(status);
764 }
765
766 SensorMap sensorMap;
767 if (!getSensorMap(connection, path, sensorMap))
768 {
769 return ipmi::responseResponseError();
770 }
771
772 IPMIThresholds thresholdData;
773 try
774 {
775 thresholdData = getIPMIThresholds(sensorMap);
776 }
777 catch (std::exception &)
778 {
779 return ipmi::responseResponseError();
780 }
781
782 uint8_t readable = 0;
783 uint8_t lowerNC = 0;
784 uint8_t lowerCritical = 0;
785 uint8_t lowerNonRecoverable = 0;
786 uint8_t upperNC = 0;
787 uint8_t upperCritical = 0;
788 uint8_t upperNonRecoverable = 0;
789
790 if (thresholdData.warningHigh)
791 {
792 readable |=
793 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
794 upperNC = *thresholdData.warningHigh;
795 }
796 if (thresholdData.warningLow)
797 {
798 readable |=
799 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
800 lowerNC = *thresholdData.warningLow;
801 }
802
803 if (thresholdData.criticalHigh)
804 {
805 readable |=
806 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
807 upperCritical = *thresholdData.criticalHigh;
808 }
809 if (thresholdData.criticalLow)
810 {
811 readable |=
812 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
813 lowerCritical = *thresholdData.criticalLow;
814 }
815
816 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
817 lowerNonRecoverable, upperNC, upperCritical,
818 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700819}
820
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000821/** @brief implements the get Sensor event enable command
822 * @param sensorNumber - sensor number
823 *
824 * @returns IPMI completion code plus response data
825 * - enabled - Sensor Event messages
826 * - assertionEnabledLsb - Assertion event messages
827 * - assertionEnabledMsb - Assertion event messages
828 * - deassertionEnabledLsb - Deassertion event messages
829 * - deassertionEnabledMsb - Deassertion event messages
830 */
831
832ipmi::RspType<uint8_t, // enabled
833 uint8_t, // assertionEnabledLsb
834 uint8_t, // assertionEnabledMsb
835 uint8_t, // deassertionEnabledLsb
836 uint8_t> // deassertionEnabledMsb
837 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700838{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700839 std::string connection;
840 std::string path;
841
Patrick Venturea41714c2019-09-25 16:59:41 -0700842 uint8_t enabled = 0;
843 uint8_t assertionEnabledLsb = 0;
844 uint8_t assertionEnabledMsb = 0;
845 uint8_t deassertionEnabledLsb = 0;
846 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000847
848 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700849 if (status)
850 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000851 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700852 }
853
854 SensorMap sensorMap;
855 if (!getSensorMap(connection, path, sensorMap))
856 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000857 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700858 }
859
860 auto warningInterface =
861 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
862 auto criticalInterface =
863 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700864 if ((warningInterface != sensorMap.end()) ||
865 (criticalInterface != sensorMap.end()))
866 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000867 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700868 IPMISensorEventEnableByte2::sensorScanningEnable);
869 if (warningInterface != sensorMap.end())
870 {
871 auto &warningMap = warningInterface->second;
872
873 auto warningHigh = warningMap.find("WarningHigh");
874 auto warningLow = warningMap.find("WarningLow");
875 if (warningHigh != warningMap.end())
876 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000877 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700878 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000879 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700880 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
881 }
882 if (warningLow != warningMap.end())
883 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000884 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700885 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000886 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700887 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
888 }
889 }
890 if (criticalInterface != sensorMap.end())
891 {
892 auto &criticalMap = criticalInterface->second;
893
894 auto criticalHigh = criticalMap.find("CriticalHigh");
895 auto criticalLow = criticalMap.find("CriticalLow");
896
897 if (criticalHigh != criticalMap.end())
898 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000899 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700900 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000901 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700902 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
903 }
904 if (criticalLow != criticalMap.end())
905 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000906 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700907 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000908 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700909 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
910 }
911 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700912 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000913
914 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
915 assertionEnabledMsb, deassertionEnabledLsb,
916 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700917}
918
919ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
920 ipmi_request_t request,
921 ipmi_response_t response,
922 ipmi_data_len_t dataLen,
923 ipmi_context_t context)
924{
925 if (*dataLen != 1)
926 {
927 *dataLen = 0;
928 return IPMI_CC_REQ_DATA_LEN_INVALID;
929 }
930 *dataLen = 0; // default to 0 in case of an error
931
932 uint8_t sensnum = *(static_cast<uint8_t *>(request));
933
934 std::string connection;
935 std::string path;
936
937 auto status = getSensorConnection(sensnum, connection, path);
938 if (status)
939 {
940 return status;
941 }
942
943 SensorMap sensorMap;
944 if (!getSensorMap(connection, path, sensorMap))
945 {
946 return IPMI_CC_RESPONSE_ERROR;
947 }
948
949 auto warningInterface =
950 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
951 auto criticalInterface =
952 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
953
954 // zero out response buff
955 auto responseClear = static_cast<uint8_t *>(response);
956 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
957 auto resp = static_cast<SensorEventStatusResp *>(response);
958 resp->enabled =
959 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
960
James Feist392786a2019-03-19 13:36:10 -0700961 std::optional<bool> criticalDeassertHigh =
962 thresholdDeassertMap[path]["CriticalAlarmHigh"];
963 std::optional<bool> criticalDeassertLow =
964 thresholdDeassertMap[path]["CriticalAlarmLow"];
965 std::optional<bool> warningDeassertHigh =
966 thresholdDeassertMap[path]["WarningAlarmHigh"];
967 std::optional<bool> warningDeassertLow =
968 thresholdDeassertMap[path]["WarningAlarmLow"];
969
970 if (criticalDeassertHigh && !*criticalDeassertHigh)
971 {
972 resp->deassertionsMSB |= static_cast<uint8_t>(
973 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
974 }
975 if (criticalDeassertLow && !*criticalDeassertLow)
976 {
977 resp->deassertionsMSB |= static_cast<uint8_t>(
978 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
979 }
980 if (warningDeassertHigh && !*warningDeassertHigh)
981 {
982 resp->deassertionsLSB |= static_cast<uint8_t>(
983 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
984 }
985 if (warningDeassertLow && !*warningDeassertLow)
986 {
987 resp->deassertionsLSB |= static_cast<uint8_t>(
988 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
989 }
990
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700991 if ((warningInterface != sensorMap.end()) ||
992 (criticalInterface != sensorMap.end()))
993 {
994 resp->enabled = static_cast<uint8_t>(
995 IPMISensorEventEnableByte2::eventMessagesEnable);
996 if (warningInterface != sensorMap.end())
997 {
998 auto &warningMap = warningInterface->second;
999
1000 auto warningHigh = warningMap.find("WarningAlarmHigh");
1001 auto warningLow = warningMap.find("WarningAlarmLow");
1002 auto warningHighAlarm = false;
1003 auto warningLowAlarm = false;
1004
1005 if (warningHigh != warningMap.end())
1006 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001007 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001008 }
1009 if (warningLow != warningMap.end())
1010 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001011 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001012 }
1013 if (warningHighAlarm)
1014 {
1015 resp->assertionsLSB |= static_cast<uint8_t>(
1016 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1017 }
1018 if (warningLowAlarm)
1019 {
1020 resp->assertionsLSB |= 1; // lower nc going low
1021 }
1022 }
1023 if (criticalInterface != sensorMap.end())
1024 {
1025 auto &criticalMap = criticalInterface->second;
1026
1027 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1028 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1029 auto criticalHighAlarm = false;
1030 auto criticalLowAlarm = false;
1031
1032 if (criticalHigh != criticalMap.end())
1033 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001034 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001035 }
1036 if (criticalLow != criticalMap.end())
1037 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001038 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001039 }
1040 if (criticalHighAlarm)
1041 {
1042 resp->assertionsMSB |= static_cast<uint8_t>(
1043 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1044 }
1045 if (criticalLowAlarm)
1046 {
1047 resp->assertionsLSB |= static_cast<uint8_t>(
1048 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1049 }
1050 }
1051 *dataLen = sizeof(SensorEventStatusResp);
1052 }
1053
1054 // no thresholds enabled, don't need assertionMSB
1055 else
1056 {
1057 *dataLen = sizeof(SensorEventStatusResp) - 1;
1058 }
1059
1060 return IPMI_CC_OK;
1061}
1062
1063/* end sensor commands */
1064
1065/* storage commands */
1066
James Feist74c50c62019-08-14 14:18:41 -07001067ipmi::RspType<uint8_t, // sdr version
1068 uint16_t, // record count
1069 uint16_t, // free space
1070 uint32_t, // most recent addition
1071 uint32_t, // most recent erase
1072 uint8_t // operationSupport
1073 >
1074 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001075{
James Feist74c50c62019-08-14 14:18:41 -07001076 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001077 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1078 {
James Feist74c50c62019-08-14 14:18:41 -07001079 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001080 }
1081
James Feist74c50c62019-08-14 14:18:41 -07001082 size_t fruCount = 0;
1083 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1084 if (ret != ipmi::ccSuccess)
1085 {
1086 return ipmi::response(ret);
1087 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001088
James Feist74c50c62019-08-14 14:18:41 -07001089 uint16_t recordCount =
1090 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001091
James Feist74c50c62019-08-14 14:18:41 -07001092 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001093 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001094
1095 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001096 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001097 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001098 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001099 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1100 unspecifiedFreeSpace, sdrLastAdd,
1101 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001102}
1103
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001104/** @brief implements the get SDR allocation info command
1105 *
1106 * @returns IPMI completion code plus response data
1107 * - allocUnits - Number of possible allocation units
1108 * - allocUnitSize - Allocation unit size in bytes.
1109 * - allocUnitFree - Number of free allocation units
1110 * - allocUnitLargestFree - Largest free block in allocation units
1111 * - maxRecordSize - Maximum record size in allocation units.
1112 */
1113ipmi::RspType<uint16_t, // allocUnits
1114 uint16_t, // allocUnitSize
1115 uint16_t, // allocUnitFree
1116 uint16_t, // allocUnitLargestFree
1117 uint8_t // maxRecordSize
1118 >
1119 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001121 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001122 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001123
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001124 constexpr uint16_t allocUnitFree = 0;
1125 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001126 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001127 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001128
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001129 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1130 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001131}
1132
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001133/** @brief implements the reserve SDR command
1134 * @returns IPMI completion code plus response data
1135 * - sdrReservationID
1136 */
1137ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001138{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001139 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001140 if (sdrReservationID == 0)
1141 {
1142 sdrReservationID++;
1143 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001144
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001145 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001146}
1147
James Feistb49a98a2019-04-16 13:48:09 -07001148ipmi::RspType<uint16_t, // next record ID
1149 std::vector<uint8_t> // payload
1150 >
1151 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1152 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001154 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001155
1156 // reservation required for partial reads with non zero offset into
1157 // record
James Feistb49a98a2019-04-16 13:48:09 -07001158 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159 {
James Feistb49a98a2019-04-16 13:48:09 -07001160 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001161 }
1162
1163 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1164 {
James Feistb49a98a2019-04-16 13:48:09 -07001165 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001166 }
1167
1168 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001169 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1170 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001171 {
James Feistb49a98a2019-04-16 13:48:09 -07001172 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173 }
1174
James Feist74c50c62019-08-14 14:18:41 -07001175 size_t lastRecord =
1176 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001177 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001178 {
James Feistb49a98a2019-04-16 13:48:09 -07001179 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001180 }
James Feistb49a98a2019-04-16 13:48:09 -07001181 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001182 {
James Feistb49a98a2019-04-16 13:48:09 -07001183 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001184 }
1185
James Feistb49a98a2019-04-16 13:48:09 -07001186 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001187
James Feistb49a98a2019-04-16 13:48:09 -07001188 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001189 {
James Feist74c50c62019-08-14 14:18:41 -07001190 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001191 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001192 if (fruIndex >= fruCount)
1193 {
James Feist74c50c62019-08-14 14:18:41 -07001194 // handle type 12 hardcoded records
1195 size_t type12Index = fruIndex - fruCount;
1196 if (type12Index >= ipmi::storage::type12Count ||
1197 offset > sizeof(Type12Record))
1198 {
1199 return ipmi::responseInvalidFieldRequest();
1200 }
1201 std::vector<uint8_t> record =
1202 ipmi::storage::getType12SDRs(type12Index, recordID);
1203 if (record.size() < (offset + bytesToRead))
1204 {
1205 bytesToRead = record.size() - offset;
1206 }
James Feistb49a98a2019-04-16 13:48:09 -07001207
James Feist74c50c62019-08-14 14:18:41 -07001208 recordData.insert(recordData.end(), record.begin() + offset,
1209 record.begin() + offset + bytesToRead);
1210 }
1211 else
1212 {
1213 // handle fru records
1214 get_sdr::SensorDataFruRecord data;
1215 if (offset > sizeof(data))
1216 {
1217 return ipmi::responseInvalidFieldRequest();
1218 }
1219 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1220 if (ret != IPMI_CC_OK)
1221 {
1222 return ipmi::response(ret);
1223 }
1224 data.header.record_id_msb = recordID << 8;
1225 data.header.record_id_lsb = recordID & 0xFF;
1226 if (sizeof(data) < (offset + bytesToRead))
1227 {
1228 bytesToRead = sizeof(data) - offset;
1229 }
1230
1231 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1232 recordData.insert(recordData.end(), respStart,
1233 respStart + bytesToRead);
1234 }
James Feistb49a98a2019-04-16 13:48:09 -07001235
1236 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001237 }
1238
1239 std::string connection;
1240 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001241 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001242 for (const auto &sensor : sensorTree)
1243 {
1244 if (sensorIndex-- == 0)
1245 {
1246 if (!sensor.second.size())
1247 {
James Feistb49a98a2019-04-16 13:48:09 -07001248 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001249 }
1250 connection = sensor.second.begin()->first;
1251 path = sensor.first;
1252 break;
1253 }
1254 }
1255
1256 SensorMap sensorMap;
1257 if (!getSensorMap(connection, path, sensorMap))
1258 {
James Feistb49a98a2019-04-16 13:48:09 -07001259 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001260 }
James Feistb49a98a2019-04-16 13:48:09 -07001261 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001262 get_sdr::SensorDataFullRecord record = {0};
1263
James Feistb49a98a2019-04-16 13:48:09 -07001264 record.header.record_id_msb = recordID << 8;
1265 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001266 record.header.sdr_version = ipmiSdrVersion;
1267 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1268 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1269 sizeof(get_sdr::SensorDataRecordHeader);
1270 record.key.owner_id = 0x20;
1271 record.key.owner_lun = 0x0;
1272 record.key.sensor_number = sensornumber;
1273
1274 record.body.entity_id = 0x0;
1275 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001276 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001277 record.body.sensor_type = getSensorTypeFromPath(path);
1278 std::string type = getSensorTypeStringFromPath(path);
1279 auto typeCstr = type.c_str();
1280 auto findUnits = sensorUnits.find(typeCstr);
1281 if (findUnits != sensorUnits.end())
1282 {
1283 record.body.sensor_units_2_base =
1284 static_cast<uint8_t>(findUnits->second);
1285 } // else default 0x0 unspecified
1286
1287 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1288
1289 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1290 if (sensorObject == sensorMap.end())
1291 {
James Feistb49a98a2019-04-16 13:48:09 -07001292 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001293 }
1294
1295 auto maxObject = sensorObject->second.find("MaxValue");
1296 auto minObject = sensorObject->second.find("MinValue");
1297 double max = 128;
1298 double min = -127;
1299 if (maxObject != sensorObject->second.end())
1300 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001301 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001302 }
1303
1304 if (minObject != sensorObject->second.end())
1305 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001306 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001307 }
1308
Yong Li1f2eb5e2019-05-23 14:07:17 +08001309 int16_t mValue = 0;
1310 int8_t rExp = 0;
1311 int16_t bValue = 0;
1312 int8_t bExp = 0;
1313 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001314
1315 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1316 {
James Feistb49a98a2019-04-16 13:48:09 -07001317 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001318 }
1319
1320 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1321 record.body.m_lsb = mValue & 0xFF;
1322
1323 // move the smallest bit of the MSB into place (bit 9)
1324 // the MSbs are bits 7:8 in m_msb_and_tolerance
1325 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1326
1327 // assign the negative
1328 if (mValue < 0)
1329 {
1330 mMsb |= (1 << 7);
1331 }
1332 record.body.m_msb_and_tolerance = mMsb;
1333
1334 record.body.b_lsb = bValue & 0xFF;
1335
1336 // move the smallest bit of the MSB into place
1337 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1338 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1339
1340 // assign the negative
1341 if (bValue < 0)
1342 {
1343 bMsb |= (1 << 7);
1344 }
1345 record.body.b_msb_and_accuracy_lsb = bMsb;
1346
1347 record.body.r_b_exponents = bExp & 0x7;
1348 if (bExp < 0)
1349 {
1350 record.body.r_b_exponents |= 1 << 3;
1351 }
1352 record.body.r_b_exponents = (rExp & 0x7) << 4;
1353 if (rExp < 0)
1354 {
1355 record.body.r_b_exponents |= 1 << 7;
1356 }
1357
1358 // todo fill out rest of units
1359 if (bSigned)
1360 {
1361 record.body.sensor_units_1 = 1 << 7;
1362 }
1363
1364 // populate sensor name from path
1365 std::string name;
1366 size_t nameStart = path.rfind("/");
1367 if (nameStart != std::string::npos)
1368 {
1369 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1370 }
1371
1372 std::replace(name.begin(), name.end(), '_', ' ');
1373 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1374 {
James Feist979a2322019-05-15 09:06:54 -07001375 // try to not truncate by replacing common words
1376 constexpr std::array<std::pair<const char *, const char *>, 2>
1377 replaceWords = {std::make_pair("Output", "Out"),
1378 std::make_pair("Input", "In")};
1379 for (const auto &[find, replace] : replaceWords)
1380 {
1381 boost::replace_all(name, find, replace);
1382 }
1383
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001384 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1385 }
1386 record.body.id_string_info = name.size();
1387 std::strncpy(record.body.id_string, name.c_str(),
1388 sizeof(record.body.id_string));
1389
James Feistc4b15bc2019-04-16 15:41:39 -07001390 IPMIThresholds thresholdData;
1391 try
1392 {
1393 thresholdData = getIPMIThresholds(sensorMap);
1394 }
1395 catch (std::exception &)
1396 {
1397 return ipmi::responseResponseError();
1398 }
1399
1400 if (thresholdData.criticalHigh)
1401 {
1402 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1403 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1404 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1405 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1406 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1407 record.body.discrete_reading_setting_mask[0] |=
1408 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1409 }
1410 if (thresholdData.warningHigh)
1411 {
1412 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1413 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1414 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1415 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1416 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1417 record.body.discrete_reading_setting_mask[0] |=
1418 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1419 }
1420 if (thresholdData.criticalLow)
1421 {
1422 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1423 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1424 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1425 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1426 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1427 record.body.discrete_reading_setting_mask[0] |=
1428 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1429 }
1430 if (thresholdData.warningLow)
1431 {
1432 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1433 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1434 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1435 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1436 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1437 record.body.discrete_reading_setting_mask[0] |=
1438 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1439 }
1440
1441 // everything that is readable is setable
1442 record.body.discrete_reading_setting_mask[1] =
1443 record.body.discrete_reading_setting_mask[0];
1444
James Feistb49a98a2019-04-16 13:48:09 -07001445 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001446 {
James Feistb49a98a2019-04-16 13:48:09 -07001447 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001448 }
1449
James Feistb49a98a2019-04-16 13:48:09 -07001450 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1451 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001452
James Feistb49a98a2019-04-16 13:48:09 -07001453 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001454}
1455/* end storage commands */
1456
1457void registerSensorFunctions()
1458{
1459 // get firmware version information
1460 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1461 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1462
1463 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001464 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1465 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001466
1467 // <Set Sensor Reading and Event Status>
1468 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001469 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001470 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1471
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001472 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001473 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1474 ipmi::sensor_event::cmdPlatformEvent,
1475 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001476
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001477 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001478 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1479 ipmi::sensor_event::cmdGetSensorReading,
1480 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001481
1482 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001483 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1484 ipmi::sensor_event::cmdGetSensorThreshold,
1485 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001486
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001487 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001488 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1489 ipmi::sensor_event::cmdSetSensorThreshold,
1490 ipmi::Privilege::Operator,
1491 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001492
1493 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001494 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1495 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001496 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001497
1498 // <Get Sensor Event Status>
1499 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001500 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1501 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001502
1503 // register all storage commands for both Sensor and Storage command
1504 // versions
1505
1506 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001507 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1508 ipmi::storage::cmdGetSdrRepositoryInfo,
1509 ipmi::Privilege::User,
1510 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001511
1512 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001513 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1514 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1515 ipmi::Privilege::User,
1516 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001517
1518 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001519 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1520 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001521 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001522
Vernon Mauery98bbf692019-09-16 11:14:59 -07001523 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1524 ipmi::storage::cmdReserveSdrRepository,
1525 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001526
1527 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001528 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1529 ipmi::sensor_event::cmdGetDeviceSdr,
1530 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001531
Vernon Mauery98bbf692019-09-16 11:14:59 -07001532 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1533 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1534 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001535}
1536} // namespace ipmi