blob: ce94d5a55c6ff0739cc8122bcdae00453bae5877 [file] [log] [blame]
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001/*
2// Copyright (c) 2017 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070017#include <boost/algorithm/string.hpp>
18#include <boost/container/flat_map.hpp>
19#include <chrono>
20#include <cmath>
21#include <commandutils.hpp>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070022#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070023#include <iostream>
Jason M. Bills99b78ec2019-01-18 10:42:18 -080024#include <ipmi_to_redfish_hooks.hpp>
James Feist2a265d52019-04-08 11:16:27 -070025#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070026#include <ipmid/utils.hpp>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070027#include <map>
Patrick Venturec4e9de62019-09-25 17:40:54 -070028#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070029#include <phosphor-logging/log.hpp>
30#include <sdbusplus/bus.hpp>
31#include <sdrutils.hpp>
32#include <sensorcommands.hpp>
33#include <sensorutils.hpp>
34#include <storagecommands.hpp>
35#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070036#include <utility>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070037
38namespace ipmi
39{
40using ManagedObjectType =
41 std::map<sdbusplus::message::object_path,
42 std::map<std::string, std::map<std::string, DbusVariant>>>;
43
44using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
45
46static constexpr int sensorListUpdatePeriod = 10;
47static constexpr int sensorMapUpdatePeriod = 2;
48
49constexpr size_t maxSDRTotalSize =
50 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
51constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
52
53static uint16_t sdrReservationID;
54static uint32_t sdrLastAdd = noTimestamp;
55static uint32_t sdrLastRemove = noTimestamp;
56
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053057SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070058static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
59
Jason M. Bills17add592018-11-12 14:30:12 -080060// Specify the comparison required to sort and find char* map objects
61struct CmpStr
62{
63 bool operator()(const char *a, const char *b) const
64 {
65 return std::strcmp(a, b) < 0;
66 }
67};
68const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
69 sensorUnits{{{"temperature", SensorUnits::degreesC},
70 {"voltage", SensorUnits::volts},
71 {"current", SensorUnits::amps},
72 {"fan_tach", SensorUnits::rpm},
73 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070074
75void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070076
77static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070078 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070079 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
80 "sensors/'",
81 [](sdbusplus::message::message &m) {
82 sensorTree.clear();
83 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
84 std::chrono::system_clock::now().time_since_epoch())
85 .count();
86 });
87
88static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070089 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070090 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
91 "sensors/'",
92 [](sdbusplus::message::message &m) {
93 sensorTree.clear();
94 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
95 std::chrono::system_clock::now().time_since_epoch())
96 .count();
97 });
98
James Feist392786a2019-03-19 13:36:10 -070099// this keeps track of deassertions for sensor event status command. A
100// deasertion can only happen if an assertion was seen first.
101static boost::container::flat_map<
102 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
103 thresholdDeassertMap;
104
105static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700106 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700107 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
108 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
109 [](sdbusplus::message::message &m) {
110 boost::container::flat_map<std::string, std::variant<bool, double>>
111 values;
112 m.read(std::string(), values);
113
114 auto findAssert =
115 std::find_if(values.begin(), values.end(), [](const auto &pair) {
116 return pair.first.find("Alarm") != std::string::npos;
117 });
118 if (findAssert != values.end())
119 {
120 auto ptr = std::get_if<bool>(&(findAssert->second));
121 if (ptr == nullptr)
122 {
123 phosphor::logging::log<phosphor::logging::level::ERR>(
124 "thresholdChanged: Assert non bool");
125 return;
126 }
127 if (*ptr)
128 {
129 phosphor::logging::log<phosphor::logging::level::INFO>(
130 "thresholdChanged: Assert",
131 phosphor::logging::entry("SENSOR=%s", m.get_path()));
132 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
133 }
134 else
135 {
136 auto &value =
137 thresholdDeassertMap[m.get_path()][findAssert->first];
138 if (value)
139 {
140 phosphor::logging::log<phosphor::logging::level::INFO>(
141 "thresholdChanged: deassert",
142 phosphor::logging::entry("SENSOR=%s", m.get_path()));
143 value = *ptr;
144 }
145 }
146 }
147 });
148
James Feistaecaef72019-04-26 10:30:32 -0700149static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
150 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700151{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700152 max = 127;
153 min = -128;
154
James Feistaecaef72019-04-26 10:30:32 -0700155 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
156 auto critical =
157 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
158 auto warning =
159 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
160
161 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700162 {
James Feistaecaef72019-04-26 10:30:32 -0700163 auto maxMap = sensorObject->second.find("MaxValue");
164 auto minMap = sensorObject->second.find("MinValue");
165
166 if (maxMap != sensorObject->second.end())
167 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700168 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700169 }
170 if (minMap != sensorObject->second.end())
171 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700172 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700173 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700174 }
James Feistaecaef72019-04-26 10:30:32 -0700175 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700176 {
James Feistaecaef72019-04-26 10:30:32 -0700177 auto lower = critical->second.find("CriticalLow");
178 auto upper = critical->second.find("CriticalHigh");
179 if (lower != critical->second.end())
180 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700181 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700182 min = std::min(value, min);
183 }
184 if (upper != critical->second.end())
185 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700186 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700187 max = std::max(value, max);
188 }
189 }
190 if (warning != sensorMap.end())
191 {
192
193 auto lower = warning->second.find("WarningLow");
194 auto upper = warning->second.find("WarningHigh");
195 if (lower != warning->second.end())
196 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700197 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700198 min = std::min(value, min);
199 }
200 if (upper != warning->second.end())
201 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700202 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700203 max = std::max(value, max);
204 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700205 }
206}
207
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700208static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
209 SensorMap &sensorMap)
210{
211 static boost::container::flat_map<
212 std::string, std::chrono::time_point<std::chrono::steady_clock>>
213 updateTimeMap;
214
215 auto updateFind = updateTimeMap.find(sensorConnection);
216 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
217 if (updateFind != updateTimeMap.end())
218 {
219 lastUpdate = updateFind->second;
220 }
221
222 auto now = std::chrono::steady_clock::now();
223
224 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
225 .count() > sensorMapUpdatePeriod)
226 {
227 updateTimeMap[sensorConnection] = now;
228
Vernon Mauery15419dd2019-05-24 09:40:30 -0700229 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
230 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700231 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
232 "GetManagedObjects");
233
234 ManagedObjectType managedObjects;
235 try
236 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700237 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700238 reply.read(managedObjects);
239 }
240 catch (sdbusplus::exception_t &)
241 {
242 phosphor::logging::log<phosphor::logging::level::ERR>(
243 "Error getting managed objects from connection",
244 phosphor::logging::entry("CONNECTION=%s",
245 sensorConnection.c_str()));
246 return false;
247 }
248
249 SensorCache[sensorConnection] = managedObjects;
250 }
251 auto connection = SensorCache.find(sensorConnection);
252 if (connection == SensorCache.end())
253 {
254 return false;
255 }
256 auto path = connection->second.find(sensorPath);
257 if (path == connection->second.end())
258 {
259 return false;
260 }
261 sensorMap = path->second;
262
263 return true;
264}
265
266/* sensor commands */
267ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
268 ipmi_request_t request,
269 ipmi_response_t response,
270 ipmi_data_len_t dataLen,
271 ipmi_context_t context)
272{
273 *dataLen = 0;
274 printCommand(+netfn, +cmd);
275 return IPMI_CC_INVALID;
276}
277
James Feist7aaf3fe2019-06-25 11:52:11 -0700278namespace meHealth
279{
280constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
281constexpr const char *path = "/xyz/openbmc_project/status/me";
282constexpr const char *interface = "xyz.openbmc_project.SetHealth";
283constexpr const char *method = "SetHealth";
284constexpr const char *critical = "critical";
285constexpr const char *warning = "warning";
286constexpr const char *ok = "ok";
287} // namespace meHealth
288
289static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
290{
291 constexpr const std::array<uint8_t, 10> critical = {
292 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
293 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
294 0x1A};
295
296 std::string state;
297 if (std::find(critical.begin(), critical.end(), eventData2) !=
298 critical.end())
299 {
300 state = meHealth::critical;
301 }
302 // special case 0x3 as we only care about a few states
303 else if (eventData2 == 0x3)
304 {
305 if (eventData3 <= 0x2)
306 {
307 state = meHealth::warning;
308 }
309 else
310 {
311 return;
312 }
313 }
314 else if (std::find(warning.begin(), warning.end(), eventData2) !=
315 warning.end())
316 {
317 state = meHealth::warning;
318 }
319 else
320 {
321 return;
322 }
323 if (disable)
324 {
325 state = meHealth::ok;
326 }
327
328 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
329 auto setHealth =
330 dbus->new_method_call(meHealth::busname, meHealth::path,
331 meHealth::interface, meHealth::method);
332 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
333 try
334 {
335 dbus->call(setHealth);
336 }
337 catch (sdbusplus::exception_t &)
338 {
339 phosphor::logging::log<phosphor::logging::level::ERR>(
340 "Failed to set ME Health");
341 }
342}
343
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700344ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
345{
James Feist7aaf3fe2019-06-25 11:52:11 -0700346 constexpr const uint8_t meId = 0x2C;
347 constexpr const uint8_t meSensorNum = 0x17;
348 constexpr const uint8_t disabled = 0x80;
349
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700350 uint8_t generatorID = 0;
351 uint8_t evmRev = 0;
352 uint8_t sensorType = 0;
353 uint8_t sensorNum = 0;
354 uint8_t eventType = 0;
355 uint8_t eventData1 = 0;
356 std::optional<uint8_t> eventData2 = 0;
357 std::optional<uint8_t> eventData3 = 0;
358
359 // todo: This check is supposed to be based on the incoming channel.
360 // e.g. system channel will provide upto 8 bytes including generator
361 // ID, but ipmb channel will provide only up to 7 bytes without the
362 // generator ID.
363 // Support for this check is coming in future patches, so for now just base
364 // it on if the first byte is the EvMRev (0x04).
365 if (p.size() && p.data()[0] == 0x04)
366 {
367 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
368 eventData2, eventData3);
369 // todo: the generator ID for this channel is supposed to come from the
370 // IPMB requesters slave address. Support for this is coming in future
371 // patches, so for now just assume it is coming from the ME (0x2C).
372 generatorID = 0x2C;
373 }
374 else
375 {
376 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
377 eventData1, eventData2, eventData3);
378 }
379 if (!p.fullyUnpacked())
380 {
381 return ipmi::responseReqDataLenInvalid();
382 }
383
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700384 // Send this request to the Redfish hooks to log it as a Redfish message
385 // instead. There is no need to add it to the SEL, so just return success.
386 intel_oem::ipmi::sel::checkRedfishHooks(
387 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
388 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700389
James Feist7aaf3fe2019-06-25 11:52:11 -0700390 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
391 eventData3)
392 {
393 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
394 }
395
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700396 return ipmi::responseSuccess();
397}
398
James Feist0cd014a2019-04-08 15:04:33 -0700399ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
400 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700401{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700402 std::string connection;
403 std::string path;
404
405 auto status = getSensorConnection(sensnum, connection, path);
406 if (status)
407 {
James Feist0cd014a2019-04-08 15:04:33 -0700408 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700409 }
410
411 SensorMap sensorMap;
412 if (!getSensorMap(connection, path, sensorMap))
413 {
James Feist0cd014a2019-04-08 15:04:33 -0700414 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700415 }
416 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
417
418 if (sensorObject == sensorMap.end() ||
419 sensorObject->second.find("Value") == sensorObject->second.end())
420 {
James Feist0cd014a2019-04-08 15:04:33 -0700421 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700422 }
James Feist0cd014a2019-04-08 15:04:33 -0700423 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700424 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700425
Yong Li1f2eb5e2019-05-23 14:07:17 +0800426 double max = 0;
427 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700428 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700429
430 int16_t mValue = 0;
431 int16_t bValue = 0;
432 int8_t rExp = 0;
433 int8_t bExp = 0;
434 bool bSigned = false;
435
436 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
437 {
James Feist0cd014a2019-04-08 15:04:33 -0700438 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700439 }
440
James Feist0cd014a2019-04-08 15:04:33 -0700441 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700442 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700443 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700444 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700445 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800446 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700447
James Feist0cd014a2019-04-08 15:04:33 -0700448 uint8_t thresholds = 0;
449
450 auto warningObject =
451 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
452 if (warningObject != sensorMap.end())
453 {
454 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
455 auto alarmLow = warningObject->second.find("WarningAlarmLow");
456 if (alarmHigh != warningObject->second.end())
457 {
458 if (std::get<bool>(alarmHigh->second))
459 {
460 thresholds |= static_cast<uint8_t>(
461 IPMISensorReadingByte3::upperNonCritical);
462 }
463 }
464 if (alarmLow != warningObject->second.end())
465 {
466 if (std::get<bool>(alarmLow->second))
467 {
468 thresholds |= static_cast<uint8_t>(
469 IPMISensorReadingByte3::lowerNonCritical);
470 }
471 }
472 }
473
474 auto criticalObject =
475 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
476 if (criticalObject != sensorMap.end())
477 {
478 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
479 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
480 if (alarmHigh != criticalObject->second.end())
481 {
482 if (std::get<bool>(alarmHigh->second))
483 {
484 thresholds |=
485 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
486 }
487 }
488 if (alarmLow != criticalObject->second.end())
489 {
490 if (std::get<bool>(alarmLow->second))
491 {
492 thresholds |=
493 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
494 }
495 }
496 }
497
498 // no discrete as of today so optional byte is never returned
499 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700500}
501
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000502/** @brief implements the Set Sensor threshold command
503 * @param sensorNumber - sensor number
504 * @param lowerNonCriticalThreshMask
505 * @param lowerCriticalThreshMask
506 * @param lowerNonRecovThreshMask
507 * @param upperNonCriticalThreshMask
508 * @param upperCriticalThreshMask
509 * @param upperNonRecovThreshMask
510 * @param reserved
511 * @param lowerNonCritical - lower non-critical threshold
512 * @param lowerCritical - Lower critical threshold
513 * @param lowerNonRecoverable - Lower non recovarable threshold
514 * @param upperNonCritical - Upper non-critical threshold
515 * @param upperCritical - Upper critical
516 * @param upperNonRecoverable - Upper Non-recoverable
517 *
518 * @returns IPMI completion code
519 */
520ipmi::RspType<> ipmiSenSetSensorThresholds(
521 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
522 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
523 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
524 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
525 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
526 uint8_t upperNonCritical, uint8_t upperCritical,
527 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700528{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000529 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700530
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000531 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700532 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000533 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700534 }
535
536 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000537 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700538 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000539 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700540 }
541
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000542 // if none of the threshold mask are set, nothing to do
543 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
544 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
545 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700546 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000547 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700548 }
549
550 std::string connection;
551 std::string path;
552
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000553 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700554 if (status)
555 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000556 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700557 }
558 SensorMap sensorMap;
559 if (!getSensorMap(connection, path, sensorMap))
560 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000561 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700562 }
563
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700564 double max = 0;
565 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700566 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700567
568 int16_t mValue = 0;
569 int16_t bValue = 0;
570 int8_t rExp = 0;
571 int8_t bExp = 0;
572 bool bSigned = false;
573
574 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
575 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000576 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700577 }
578
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700579 // store a vector of property name, value to set, and interface
580 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
581
582 // define the indexes of the tuple
583 constexpr uint8_t propertyName = 0;
584 constexpr uint8_t thresholdValue = 1;
585 constexpr uint8_t interface = 2;
586 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000587 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700588 {
589 auto findThreshold =
590 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
591 if (findThreshold == sensorMap.end())
592 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000593 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700594 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000595 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700596 {
597 auto findLower = findThreshold->second.find("CriticalLow");
598 if (findLower == findThreshold->second.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 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700603 findThreshold->first);
604 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000605 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700606 {
607 auto findUpper = findThreshold->second.find("CriticalHigh");
608 if (findUpper == findThreshold->second.end())
609 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000610 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700611 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000612 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700613 findThreshold->first);
614 }
615 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000616 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700617 {
618 auto findThreshold =
619 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
620 if (findThreshold == sensorMap.end())
621 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000622 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700623 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000624 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700625 {
626 auto findLower = findThreshold->second.find("WarningLow");
627 if (findLower == findThreshold->second.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 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700632 findThreshold->first);
633 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000634 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700635 {
636 auto findUpper = findThreshold->second.find("WarningHigh");
637 if (findUpper == findThreshold->second.end())
638 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000639 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700640 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000641 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700642 findThreshold->first);
643 }
644 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700645 for (const auto &property : thresholdsToSet)
646 {
647 // from section 36.3 in the IPMI Spec, assume all linear
648 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
649 (bValue * std::pow(10, bExp))) *
650 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700651 setDbusProperty(
652 *getSdBus(), connection, path, std::get<interface>(property),
653 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700654 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000655 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700656}
657
James Feist902c4c52019-04-16 14:51:31 -0700658IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700659{
James Feist902c4c52019-04-16 14:51:31 -0700660 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700661 auto warningInterface =
662 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
663 auto criticalInterface =
664 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
665
666 if ((warningInterface != sensorMap.end()) ||
667 (criticalInterface != sensorMap.end()))
668 {
669 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
670
671 if (sensorPair == sensorMap.end())
672 {
673 // should not have been able to find a sensor not implementing
674 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700675 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700676 }
677
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800678 double max = 0;
679 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700680 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700681
682 int16_t mValue = 0;
683 int16_t bValue = 0;
684 int8_t rExp = 0;
685 int8_t bExp = 0;
686 bool bSigned = false;
687
688 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
689 {
James Feist902c4c52019-04-16 14:51:31 -0700690 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700691 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700692 if (warningInterface != sensorMap.end())
693 {
694 auto &warningMap = warningInterface->second;
695
696 auto warningHigh = warningMap.find("WarningHigh");
697 auto warningLow = warningMap.find("WarningLow");
698
699 if (warningHigh != warningMap.end())
700 {
James Feist902c4c52019-04-16 14:51:31 -0700701
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700702 double value =
703 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700704 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700705 value, mValue, rExp, bValue, bExp, bSigned);
706 }
707 if (warningLow != warningMap.end())
708 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700709 double value =
710 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700711 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700712 value, mValue, rExp, bValue, bExp, bSigned);
713 }
714 }
715 if (criticalInterface != sensorMap.end())
716 {
717 auto &criticalMap = criticalInterface->second;
718
719 auto criticalHigh = criticalMap.find("CriticalHigh");
720 auto criticalLow = criticalMap.find("CriticalLow");
721
722 if (criticalHigh != criticalMap.end())
723 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700724 double value =
725 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700726 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700727 value, mValue, rExp, bValue, bExp, bSigned);
728 }
729 if (criticalLow != criticalMap.end())
730 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700731 double value =
732 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700733 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700734 value, mValue, rExp, bValue, bExp, bSigned);
735 }
736 }
737 }
James Feist902c4c52019-04-16 14:51:31 -0700738 return resp;
739}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700740
James Feist902c4c52019-04-16 14:51:31 -0700741ipmi::RspType<uint8_t, // readable
742 uint8_t, // lowerNCrit
743 uint8_t, // lowerCrit
744 uint8_t, // lowerNrecoverable
745 uint8_t, // upperNC
746 uint8_t, // upperCrit
747 uint8_t> // upperNRecoverable
748 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
749{
750 std::string connection;
751 std::string path;
752
753 auto status = getSensorConnection(sensorNumber, connection, path);
754 if (status)
755 {
756 return ipmi::response(status);
757 }
758
759 SensorMap sensorMap;
760 if (!getSensorMap(connection, path, sensorMap))
761 {
762 return ipmi::responseResponseError();
763 }
764
765 IPMIThresholds thresholdData;
766 try
767 {
768 thresholdData = getIPMIThresholds(sensorMap);
769 }
770 catch (std::exception &)
771 {
772 return ipmi::responseResponseError();
773 }
774
775 uint8_t readable = 0;
776 uint8_t lowerNC = 0;
777 uint8_t lowerCritical = 0;
778 uint8_t lowerNonRecoverable = 0;
779 uint8_t upperNC = 0;
780 uint8_t upperCritical = 0;
781 uint8_t upperNonRecoverable = 0;
782
783 if (thresholdData.warningHigh)
784 {
785 readable |=
786 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
787 upperNC = *thresholdData.warningHigh;
788 }
789 if (thresholdData.warningLow)
790 {
791 readable |=
792 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
793 lowerNC = *thresholdData.warningLow;
794 }
795
796 if (thresholdData.criticalHigh)
797 {
798 readable |=
799 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
800 upperCritical = *thresholdData.criticalHigh;
801 }
802 if (thresholdData.criticalLow)
803 {
804 readable |=
805 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
806 lowerCritical = *thresholdData.criticalLow;
807 }
808
809 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
810 lowerNonRecoverable, upperNC, upperCritical,
811 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700812}
813
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000814/** @brief implements the get Sensor event enable command
815 * @param sensorNumber - sensor number
816 *
817 * @returns IPMI completion code plus response data
818 * - enabled - Sensor Event messages
819 * - assertionEnabledLsb - Assertion event messages
820 * - assertionEnabledMsb - Assertion event messages
821 * - deassertionEnabledLsb - Deassertion event messages
822 * - deassertionEnabledMsb - Deassertion event messages
823 */
824
825ipmi::RspType<uint8_t, // enabled
826 uint8_t, // assertionEnabledLsb
827 uint8_t, // assertionEnabledMsb
828 uint8_t, // deassertionEnabledLsb
829 uint8_t> // deassertionEnabledMsb
830 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700831{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700832 std::string connection;
833 std::string path;
834
Patrick Venturea41714c2019-09-25 16:59:41 -0700835 uint8_t enabled = 0;
836 uint8_t assertionEnabledLsb = 0;
837 uint8_t assertionEnabledMsb = 0;
838 uint8_t deassertionEnabledLsb = 0;
839 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000840
841 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700842 if (status)
843 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000844 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700845 }
846
847 SensorMap sensorMap;
848 if (!getSensorMap(connection, path, sensorMap))
849 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000850 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700851 }
852
853 auto warningInterface =
854 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
855 auto criticalInterface =
856 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700857 if ((warningInterface != sensorMap.end()) ||
858 (criticalInterface != sensorMap.end()))
859 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000860 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700861 IPMISensorEventEnableByte2::sensorScanningEnable);
862 if (warningInterface != sensorMap.end())
863 {
864 auto &warningMap = warningInterface->second;
865
866 auto warningHigh = warningMap.find("WarningHigh");
867 auto warningLow = warningMap.find("WarningLow");
868 if (warningHigh != warningMap.end())
869 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000870 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700871 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000872 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700873 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
874 }
875 if (warningLow != 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::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000879 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700880 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
881 }
882 }
883 if (criticalInterface != sensorMap.end())
884 {
885 auto &criticalMap = criticalInterface->second;
886
887 auto criticalHigh = criticalMap.find("CriticalHigh");
888 auto criticalLow = criticalMap.find("CriticalLow");
889
890 if (criticalHigh != criticalMap.end())
891 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000892 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700893 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000894 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700895 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
896 }
897 if (criticalLow != criticalMap.end())
898 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000899 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700900 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000901 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700902 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
903 }
904 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700905 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000906
907 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
908 assertionEnabledMsb, deassertionEnabledLsb,
909 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700910}
911
912ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
913 ipmi_request_t request,
914 ipmi_response_t response,
915 ipmi_data_len_t dataLen,
916 ipmi_context_t context)
917{
918 if (*dataLen != 1)
919 {
920 *dataLen = 0;
921 return IPMI_CC_REQ_DATA_LEN_INVALID;
922 }
923 *dataLen = 0; // default to 0 in case of an error
924
925 uint8_t sensnum = *(static_cast<uint8_t *>(request));
926
927 std::string connection;
928 std::string path;
929
930 auto status = getSensorConnection(sensnum, connection, path);
931 if (status)
932 {
933 return status;
934 }
935
936 SensorMap sensorMap;
937 if (!getSensorMap(connection, path, sensorMap))
938 {
939 return IPMI_CC_RESPONSE_ERROR;
940 }
941
942 auto warningInterface =
943 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
944 auto criticalInterface =
945 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
946
947 // zero out response buff
948 auto responseClear = static_cast<uint8_t *>(response);
949 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
950 auto resp = static_cast<SensorEventStatusResp *>(response);
951 resp->enabled =
952 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
953
James Feist392786a2019-03-19 13:36:10 -0700954 std::optional<bool> criticalDeassertHigh =
955 thresholdDeassertMap[path]["CriticalAlarmHigh"];
956 std::optional<bool> criticalDeassertLow =
957 thresholdDeassertMap[path]["CriticalAlarmLow"];
958 std::optional<bool> warningDeassertHigh =
959 thresholdDeassertMap[path]["WarningAlarmHigh"];
960 std::optional<bool> warningDeassertLow =
961 thresholdDeassertMap[path]["WarningAlarmLow"];
962
963 if (criticalDeassertHigh && !*criticalDeassertHigh)
964 {
965 resp->deassertionsMSB |= static_cast<uint8_t>(
966 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
967 }
968 if (criticalDeassertLow && !*criticalDeassertLow)
969 {
970 resp->deassertionsMSB |= static_cast<uint8_t>(
971 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
972 }
973 if (warningDeassertHigh && !*warningDeassertHigh)
974 {
975 resp->deassertionsLSB |= static_cast<uint8_t>(
976 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
977 }
978 if (warningDeassertLow && !*warningDeassertLow)
979 {
980 resp->deassertionsLSB |= static_cast<uint8_t>(
981 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
982 }
983
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700984 if ((warningInterface != sensorMap.end()) ||
985 (criticalInterface != sensorMap.end()))
986 {
987 resp->enabled = static_cast<uint8_t>(
988 IPMISensorEventEnableByte2::eventMessagesEnable);
989 if (warningInterface != sensorMap.end())
990 {
991 auto &warningMap = warningInterface->second;
992
993 auto warningHigh = warningMap.find("WarningAlarmHigh");
994 auto warningLow = warningMap.find("WarningAlarmLow");
995 auto warningHighAlarm = false;
996 auto warningLowAlarm = false;
997
998 if (warningHigh != warningMap.end())
999 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001000 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001001 }
1002 if (warningLow != warningMap.end())
1003 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001004 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001005 }
1006 if (warningHighAlarm)
1007 {
1008 resp->assertionsLSB |= static_cast<uint8_t>(
1009 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1010 }
1011 if (warningLowAlarm)
1012 {
1013 resp->assertionsLSB |= 1; // lower nc going low
1014 }
1015 }
1016 if (criticalInterface != sensorMap.end())
1017 {
1018 auto &criticalMap = criticalInterface->second;
1019
1020 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1021 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1022 auto criticalHighAlarm = false;
1023 auto criticalLowAlarm = false;
1024
1025 if (criticalHigh != criticalMap.end())
1026 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001027 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001028 }
1029 if (criticalLow != criticalMap.end())
1030 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001031 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001032 }
1033 if (criticalHighAlarm)
1034 {
1035 resp->assertionsMSB |= static_cast<uint8_t>(
1036 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1037 }
1038 if (criticalLowAlarm)
1039 {
1040 resp->assertionsLSB |= static_cast<uint8_t>(
1041 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1042 }
1043 }
1044 *dataLen = sizeof(SensorEventStatusResp);
1045 }
1046
1047 // no thresholds enabled, don't need assertionMSB
1048 else
1049 {
1050 *dataLen = sizeof(SensorEventStatusResp) - 1;
1051 }
1052
1053 return IPMI_CC_OK;
1054}
1055
1056/* end sensor commands */
1057
1058/* storage commands */
1059
James Feist74c50c62019-08-14 14:18:41 -07001060ipmi::RspType<uint8_t, // sdr version
1061 uint16_t, // record count
1062 uint16_t, // free space
1063 uint32_t, // most recent addition
1064 uint32_t, // most recent erase
1065 uint8_t // operationSupport
1066 >
1067 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001068{
James Feist74c50c62019-08-14 14:18:41 -07001069 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001070 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1071 {
James Feist74c50c62019-08-14 14:18:41 -07001072 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001073 }
1074
James Feist74c50c62019-08-14 14:18:41 -07001075 size_t fruCount = 0;
1076 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1077 if (ret != ipmi::ccSuccess)
1078 {
1079 return ipmi::response(ret);
1080 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001081
James Feist74c50c62019-08-14 14:18:41 -07001082 uint16_t recordCount =
1083 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001084
James Feist74c50c62019-08-14 14:18:41 -07001085 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001086 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001087
1088 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001090 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001091 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001092 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1093 unspecifiedFreeSpace, sdrLastAdd,
1094 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001095}
1096
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001097/** @brief implements the get SDR allocation info command
1098 *
1099 * @returns IPMI completion code plus response data
1100 * - allocUnits - Number of possible allocation units
1101 * - allocUnitSize - Allocation unit size in bytes.
1102 * - allocUnitFree - Number of free allocation units
1103 * - allocUnitLargestFree - Largest free block in allocation units
1104 * - maxRecordSize - Maximum record size in allocation units.
1105 */
1106ipmi::RspType<uint16_t, // allocUnits
1107 uint16_t, // allocUnitSize
1108 uint16_t, // allocUnitFree
1109 uint16_t, // allocUnitLargestFree
1110 uint8_t // maxRecordSize
1111 >
1112 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001113{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001114 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001115 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001116
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001117 constexpr uint16_t allocUnitFree = 0;
1118 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001119 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001120 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001121
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001122 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1123 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001124}
1125
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001126/** @brief implements the reserve SDR command
1127 * @returns IPMI completion code plus response data
1128 * - sdrReservationID
1129 */
1130ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001131{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001132 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001133 if (sdrReservationID == 0)
1134 {
1135 sdrReservationID++;
1136 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001137
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001138 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001139}
1140
James Feistb49a98a2019-04-16 13:48:09 -07001141ipmi::RspType<uint16_t, // next record ID
1142 std::vector<uint8_t> // payload
1143 >
1144 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1145 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001146{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001147 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001148
1149 // reservation required for partial reads with non zero offset into
1150 // record
James Feistb49a98a2019-04-16 13:48:09 -07001151 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001152 {
James Feistb49a98a2019-04-16 13:48:09 -07001153 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001154 }
1155
1156 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1157 {
James Feistb49a98a2019-04-16 13:48:09 -07001158 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159 }
1160
1161 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001162 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1163 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001164 {
James Feistb49a98a2019-04-16 13:48:09 -07001165 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001166 }
1167
James Feist74c50c62019-08-14 14:18:41 -07001168 size_t lastRecord =
1169 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001170 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001171 {
James Feistb49a98a2019-04-16 13:48:09 -07001172 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173 }
James Feistb49a98a2019-04-16 13:48:09 -07001174 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001175 {
James Feistb49a98a2019-04-16 13:48:09 -07001176 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001177 }
1178
James Feistb49a98a2019-04-16 13:48:09 -07001179 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001180
James Feistb49a98a2019-04-16 13:48:09 -07001181 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001182 {
James Feist74c50c62019-08-14 14:18:41 -07001183 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001184 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001185 if (fruIndex >= fruCount)
1186 {
James Feist74c50c62019-08-14 14:18:41 -07001187 // handle type 12 hardcoded records
1188 size_t type12Index = fruIndex - fruCount;
1189 if (type12Index >= ipmi::storage::type12Count ||
1190 offset > sizeof(Type12Record))
1191 {
1192 return ipmi::responseInvalidFieldRequest();
1193 }
1194 std::vector<uint8_t> record =
1195 ipmi::storage::getType12SDRs(type12Index, recordID);
1196 if (record.size() < (offset + bytesToRead))
1197 {
1198 bytesToRead = record.size() - offset;
1199 }
James Feistb49a98a2019-04-16 13:48:09 -07001200
James Feist74c50c62019-08-14 14:18:41 -07001201 recordData.insert(recordData.end(), record.begin() + offset,
1202 record.begin() + offset + bytesToRead);
1203 }
1204 else
1205 {
1206 // handle fru records
1207 get_sdr::SensorDataFruRecord data;
1208 if (offset > sizeof(data))
1209 {
1210 return ipmi::responseInvalidFieldRequest();
1211 }
1212 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1213 if (ret != IPMI_CC_OK)
1214 {
1215 return ipmi::response(ret);
1216 }
1217 data.header.record_id_msb = recordID << 8;
1218 data.header.record_id_lsb = recordID & 0xFF;
1219 if (sizeof(data) < (offset + bytesToRead))
1220 {
1221 bytesToRead = sizeof(data) - offset;
1222 }
1223
1224 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1225 recordData.insert(recordData.end(), respStart,
1226 respStart + bytesToRead);
1227 }
James Feistb49a98a2019-04-16 13:48:09 -07001228
1229 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001230 }
1231
1232 std::string connection;
1233 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001234 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001235 for (const auto &sensor : sensorTree)
1236 {
1237 if (sensorIndex-- == 0)
1238 {
1239 if (!sensor.second.size())
1240 {
James Feistb49a98a2019-04-16 13:48:09 -07001241 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001242 }
1243 connection = sensor.second.begin()->first;
1244 path = sensor.first;
1245 break;
1246 }
1247 }
1248
1249 SensorMap sensorMap;
1250 if (!getSensorMap(connection, path, sensorMap))
1251 {
James Feistb49a98a2019-04-16 13:48:09 -07001252 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001253 }
James Feistb49a98a2019-04-16 13:48:09 -07001254 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001255 get_sdr::SensorDataFullRecord record = {0};
1256
James Feistb49a98a2019-04-16 13:48:09 -07001257 record.header.record_id_msb = recordID << 8;
1258 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001259 record.header.sdr_version = ipmiSdrVersion;
1260 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1261 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1262 sizeof(get_sdr::SensorDataRecordHeader);
1263 record.key.owner_id = 0x20;
1264 record.key.owner_lun = 0x0;
1265 record.key.sensor_number = sensornumber;
1266
1267 record.body.entity_id = 0x0;
1268 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001269 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001270 record.body.sensor_type = getSensorTypeFromPath(path);
1271 std::string type = getSensorTypeStringFromPath(path);
1272 auto typeCstr = type.c_str();
1273 auto findUnits = sensorUnits.find(typeCstr);
1274 if (findUnits != sensorUnits.end())
1275 {
1276 record.body.sensor_units_2_base =
1277 static_cast<uint8_t>(findUnits->second);
1278 } // else default 0x0 unspecified
1279
1280 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1281
1282 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1283 if (sensorObject == sensorMap.end())
1284 {
James Feistb49a98a2019-04-16 13:48:09 -07001285 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001286 }
1287
1288 auto maxObject = sensorObject->second.find("MaxValue");
1289 auto minObject = sensorObject->second.find("MinValue");
1290 double max = 128;
1291 double min = -127;
1292 if (maxObject != sensorObject->second.end())
1293 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001294 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001295 }
1296
1297 if (minObject != sensorObject->second.end())
1298 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001299 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001300 }
1301
Yong Li1f2eb5e2019-05-23 14:07:17 +08001302 int16_t mValue = 0;
1303 int8_t rExp = 0;
1304 int16_t bValue = 0;
1305 int8_t bExp = 0;
1306 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001307
1308 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1309 {
James Feistb49a98a2019-04-16 13:48:09 -07001310 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001311 }
1312
1313 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1314 record.body.m_lsb = mValue & 0xFF;
1315
1316 // move the smallest bit of the MSB into place (bit 9)
1317 // the MSbs are bits 7:8 in m_msb_and_tolerance
1318 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1319
1320 // assign the negative
1321 if (mValue < 0)
1322 {
1323 mMsb |= (1 << 7);
1324 }
1325 record.body.m_msb_and_tolerance = mMsb;
1326
1327 record.body.b_lsb = bValue & 0xFF;
1328
1329 // move the smallest bit of the MSB into place
1330 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1331 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1332
1333 // assign the negative
1334 if (bValue < 0)
1335 {
1336 bMsb |= (1 << 7);
1337 }
1338 record.body.b_msb_and_accuracy_lsb = bMsb;
1339
1340 record.body.r_b_exponents = bExp & 0x7;
1341 if (bExp < 0)
1342 {
1343 record.body.r_b_exponents |= 1 << 3;
1344 }
1345 record.body.r_b_exponents = (rExp & 0x7) << 4;
1346 if (rExp < 0)
1347 {
1348 record.body.r_b_exponents |= 1 << 7;
1349 }
1350
1351 // todo fill out rest of units
1352 if (bSigned)
1353 {
1354 record.body.sensor_units_1 = 1 << 7;
1355 }
1356
1357 // populate sensor name from path
1358 std::string name;
1359 size_t nameStart = path.rfind("/");
1360 if (nameStart != std::string::npos)
1361 {
1362 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1363 }
1364
1365 std::replace(name.begin(), name.end(), '_', ' ');
1366 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1367 {
James Feist979a2322019-05-15 09:06:54 -07001368 // try to not truncate by replacing common words
1369 constexpr std::array<std::pair<const char *, const char *>, 2>
1370 replaceWords = {std::make_pair("Output", "Out"),
1371 std::make_pair("Input", "In")};
1372 for (const auto &[find, replace] : replaceWords)
1373 {
1374 boost::replace_all(name, find, replace);
1375 }
1376
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001377 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1378 }
1379 record.body.id_string_info = name.size();
1380 std::strncpy(record.body.id_string, name.c_str(),
1381 sizeof(record.body.id_string));
1382
James Feistc4b15bc2019-04-16 15:41:39 -07001383 IPMIThresholds thresholdData;
1384 try
1385 {
1386 thresholdData = getIPMIThresholds(sensorMap);
1387 }
1388 catch (std::exception &)
1389 {
1390 return ipmi::responseResponseError();
1391 }
1392
1393 if (thresholdData.criticalHigh)
1394 {
1395 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1396 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1397 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1398 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1399 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1400 record.body.discrete_reading_setting_mask[0] |=
1401 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1402 }
1403 if (thresholdData.warningHigh)
1404 {
1405 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1406 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1407 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1408 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1409 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1410 record.body.discrete_reading_setting_mask[0] |=
1411 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1412 }
1413 if (thresholdData.criticalLow)
1414 {
1415 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1416 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1417 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1418 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1419 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1420 record.body.discrete_reading_setting_mask[0] |=
1421 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1422 }
1423 if (thresholdData.warningLow)
1424 {
1425 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1426 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1427 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1428 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1429 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1430 record.body.discrete_reading_setting_mask[0] |=
1431 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1432 }
1433
1434 // everything that is readable is setable
1435 record.body.discrete_reading_setting_mask[1] =
1436 record.body.discrete_reading_setting_mask[0];
1437
James Feistb49a98a2019-04-16 13:48:09 -07001438 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001439 {
James Feistb49a98a2019-04-16 13:48:09 -07001440 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001441 }
1442
James Feistb49a98a2019-04-16 13:48:09 -07001443 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1444 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001445
James Feistb49a98a2019-04-16 13:48:09 -07001446 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001447}
1448/* end storage commands */
1449
1450void registerSensorFunctions()
1451{
1452 // get firmware version information
1453 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1454 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1455
1456 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001457 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1458 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001459
1460 // <Set Sensor Reading and Event Status>
1461 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001462 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001463 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1464
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001465 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001466 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1467 ipmi::sensor_event::cmdPlatformEvent,
1468 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001469
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001470 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001471 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1472 ipmi::sensor_event::cmdGetSensorReading,
1473 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001474
1475 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001476 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1477 ipmi::sensor_event::cmdGetSensorThreshold,
1478 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001479
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001480 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001481 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1482 ipmi::sensor_event::cmdSetSensorThreshold,
1483 ipmi::Privilege::Operator,
1484 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001485
1486 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001487 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1488 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001489 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001490
1491 // <Get Sensor Event Status>
1492 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001493 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1494 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001495
1496 // register all storage commands for both Sensor and Storage command
1497 // versions
1498
1499 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001500 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1501 ipmi::storage::cmdGetSdrRepositoryInfo,
1502 ipmi::Privilege::User,
1503 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001504
1505 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001506 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1507 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1508 ipmi::Privilege::User,
1509 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001510
1511 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001512 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1513 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001514 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001515
Vernon Mauery98bbf692019-09-16 11:14:59 -07001516 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1517 ipmi::storage::cmdReserveSdrRepository,
1518 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001519
1520 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001521 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1522 ipmi::sensor_event::cmdGetDeviceSdr,
1523 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001524
Vernon Mauery98bbf692019-09-16 11:14:59 -07001525 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1526 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1527 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001528}
1529} // namespace ipmi