blob: b2490d5205fc7abe6c710aa2447bfb43e0adaa29 [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>
22#include <iostream>
Jason M. Bills99b78ec2019-01-18 10:42:18 -080023#include <ipmi_to_redfish_hooks.hpp>
James Feist2a265d52019-04-08 11:16:27 -070024#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070025#include <ipmid/utils.hpp>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070026#include <map>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070027#include <phosphor-logging/log.hpp>
28#include <sdbusplus/bus.hpp>
29#include <sdrutils.hpp>
30#include <sensorcommands.hpp>
31#include <sensorutils.hpp>
32#include <storagecommands.hpp>
33#include <string>
34
35namespace ipmi
36{
37using ManagedObjectType =
38 std::map<sdbusplus::message::object_path,
39 std::map<std::string, std::map<std::string, DbusVariant>>>;
40
41using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
42
43static constexpr int sensorListUpdatePeriod = 10;
44static constexpr int sensorMapUpdatePeriod = 2;
45
46constexpr size_t maxSDRTotalSize =
47 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
48constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
49
50static uint16_t sdrReservationID;
51static uint32_t sdrLastAdd = noTimestamp;
52static uint32_t sdrLastRemove = noTimestamp;
53
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053054SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070055static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
56
Jason M. Bills17add592018-11-12 14:30:12 -080057// Specify the comparison required to sort and find char* map objects
58struct CmpStr
59{
60 bool operator()(const char *a, const char *b) const
61 {
62 return std::strcmp(a, b) < 0;
63 }
64};
65const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
66 sensorUnits{{{"temperature", SensorUnits::degreesC},
67 {"voltage", SensorUnits::volts},
68 {"current", SensorUnits::amps},
69 {"fan_tach", SensorUnits::rpm},
70 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070071
72void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070073
74static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070075 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070076 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
77 "sensors/'",
78 [](sdbusplus::message::message &m) {
79 sensorTree.clear();
80 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
81 std::chrono::system_clock::now().time_since_epoch())
82 .count();
83 });
84
85static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070086 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070087 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
88 "sensors/'",
89 [](sdbusplus::message::message &m) {
90 sensorTree.clear();
91 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
92 std::chrono::system_clock::now().time_since_epoch())
93 .count();
94 });
95
James Feist392786a2019-03-19 13:36:10 -070096// this keeps track of deassertions for sensor event status command. A
97// deasertion can only happen if an assertion was seen first.
98static boost::container::flat_map<
99 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
100 thresholdDeassertMap;
101
102static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700103 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700104 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
105 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
106 [](sdbusplus::message::message &m) {
107 boost::container::flat_map<std::string, std::variant<bool, double>>
108 values;
109 m.read(std::string(), values);
110
111 auto findAssert =
112 std::find_if(values.begin(), values.end(), [](const auto &pair) {
113 return pair.first.find("Alarm") != std::string::npos;
114 });
115 if (findAssert != values.end())
116 {
117 auto ptr = std::get_if<bool>(&(findAssert->second));
118 if (ptr == nullptr)
119 {
120 phosphor::logging::log<phosphor::logging::level::ERR>(
121 "thresholdChanged: Assert non bool");
122 return;
123 }
124 if (*ptr)
125 {
126 phosphor::logging::log<phosphor::logging::level::INFO>(
127 "thresholdChanged: Assert",
128 phosphor::logging::entry("SENSOR=%s", m.get_path()));
129 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
130 }
131 else
132 {
133 auto &value =
134 thresholdDeassertMap[m.get_path()][findAssert->first];
135 if (value)
136 {
137 phosphor::logging::log<phosphor::logging::level::INFO>(
138 "thresholdChanged: deassert",
139 phosphor::logging::entry("SENSOR=%s", m.get_path()));
140 value = *ptr;
141 }
142 }
143 }
144 });
145
James Feistaecaef72019-04-26 10:30:32 -0700146static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
147 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700148{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700149 max = 127;
150 min = -128;
151
James Feistaecaef72019-04-26 10:30:32 -0700152 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
153 auto critical =
154 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
155 auto warning =
156 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
157
158 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700159 {
James Feistaecaef72019-04-26 10:30:32 -0700160 auto maxMap = sensorObject->second.find("MaxValue");
161 auto minMap = sensorObject->second.find("MinValue");
162
163 if (maxMap != sensorObject->second.end())
164 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700165 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700166 }
167 if (minMap != sensorObject->second.end())
168 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700169 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700170 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700171 }
James Feistaecaef72019-04-26 10:30:32 -0700172 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700173 {
James Feistaecaef72019-04-26 10:30:32 -0700174 auto lower = critical->second.find("CriticalLow");
175 auto upper = critical->second.find("CriticalHigh");
176 if (lower != critical->second.end())
177 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700178 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700179 min = std::min(value, min);
180 }
181 if (upper != critical->second.end())
182 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700183 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700184 max = std::max(value, max);
185 }
186 }
187 if (warning != sensorMap.end())
188 {
189
190 auto lower = warning->second.find("WarningLow");
191 auto upper = warning->second.find("WarningHigh");
192 if (lower != warning->second.end())
193 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700194 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700195 min = std::min(value, min);
196 }
197 if (upper != warning->second.end())
198 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700199 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700200 max = std::max(value, max);
201 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700202 }
203}
204
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700205static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
206 SensorMap &sensorMap)
207{
208 static boost::container::flat_map<
209 std::string, std::chrono::time_point<std::chrono::steady_clock>>
210 updateTimeMap;
211
212 auto updateFind = updateTimeMap.find(sensorConnection);
213 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
214 if (updateFind != updateTimeMap.end())
215 {
216 lastUpdate = updateFind->second;
217 }
218
219 auto now = std::chrono::steady_clock::now();
220
221 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
222 .count() > sensorMapUpdatePeriod)
223 {
224 updateTimeMap[sensorConnection] = now;
225
Vernon Mauery15419dd2019-05-24 09:40:30 -0700226 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
227 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700228 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
229 "GetManagedObjects");
230
231 ManagedObjectType managedObjects;
232 try
233 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700234 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700235 reply.read(managedObjects);
236 }
237 catch (sdbusplus::exception_t &)
238 {
239 phosphor::logging::log<phosphor::logging::level::ERR>(
240 "Error getting managed objects from connection",
241 phosphor::logging::entry("CONNECTION=%s",
242 sensorConnection.c_str()));
243 return false;
244 }
245
246 SensorCache[sensorConnection] = managedObjects;
247 }
248 auto connection = SensorCache.find(sensorConnection);
249 if (connection == SensorCache.end())
250 {
251 return false;
252 }
253 auto path = connection->second.find(sensorPath);
254 if (path == connection->second.end())
255 {
256 return false;
257 }
258 sensorMap = path->second;
259
260 return true;
261}
262
263/* sensor commands */
264ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
265 ipmi_request_t request,
266 ipmi_response_t response,
267 ipmi_data_len_t dataLen,
268 ipmi_context_t context)
269{
270 *dataLen = 0;
271 printCommand(+netfn, +cmd);
272 return IPMI_CC_INVALID;
273}
274
James Feist7aaf3fe2019-06-25 11:52:11 -0700275namespace meHealth
276{
277constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
278constexpr const char *path = "/xyz/openbmc_project/status/me";
279constexpr const char *interface = "xyz.openbmc_project.SetHealth";
280constexpr const char *method = "SetHealth";
281constexpr const char *critical = "critical";
282constexpr const char *warning = "warning";
283constexpr const char *ok = "ok";
284} // namespace meHealth
285
286static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
287{
288 constexpr const std::array<uint8_t, 10> critical = {
289 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
290 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
291 0x1A};
292
293 std::string state;
294 if (std::find(critical.begin(), critical.end(), eventData2) !=
295 critical.end())
296 {
297 state = meHealth::critical;
298 }
299 // special case 0x3 as we only care about a few states
300 else if (eventData2 == 0x3)
301 {
302 if (eventData3 <= 0x2)
303 {
304 state = meHealth::warning;
305 }
306 else
307 {
308 return;
309 }
310 }
311 else if (std::find(warning.begin(), warning.end(), eventData2) !=
312 warning.end())
313 {
314 state = meHealth::warning;
315 }
316 else
317 {
318 return;
319 }
320 if (disable)
321 {
322 state = meHealth::ok;
323 }
324
325 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
326 auto setHealth =
327 dbus->new_method_call(meHealth::busname, meHealth::path,
328 meHealth::interface, meHealth::method);
329 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
330 try
331 {
332 dbus->call(setHealth);
333 }
334 catch (sdbusplus::exception_t &)
335 {
336 phosphor::logging::log<phosphor::logging::level::ERR>(
337 "Failed to set ME Health");
338 }
339}
340
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700341ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
342{
James Feist7aaf3fe2019-06-25 11:52:11 -0700343 constexpr const uint8_t meId = 0x2C;
344 constexpr const uint8_t meSensorNum = 0x17;
345 constexpr const uint8_t disabled = 0x80;
346
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700347 uint8_t generatorID = 0;
348 uint8_t evmRev = 0;
349 uint8_t sensorType = 0;
350 uint8_t sensorNum = 0;
351 uint8_t eventType = 0;
352 uint8_t eventData1 = 0;
353 std::optional<uint8_t> eventData2 = 0;
354 std::optional<uint8_t> eventData3 = 0;
355
356 // todo: This check is supposed to be based on the incoming channel.
357 // e.g. system channel will provide upto 8 bytes including generator
358 // ID, but ipmb channel will provide only up to 7 bytes without the
359 // generator ID.
360 // Support for this check is coming in future patches, so for now just base
361 // it on if the first byte is the EvMRev (0x04).
362 if (p.size() && p.data()[0] == 0x04)
363 {
364 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
365 eventData2, eventData3);
366 // todo: the generator ID for this channel is supposed to come from the
367 // IPMB requesters slave address. Support for this is coming in future
368 // patches, so for now just assume it is coming from the ME (0x2C).
369 generatorID = 0x2C;
370 }
371 else
372 {
373 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
374 eventData1, eventData2, eventData3);
375 }
376 if (!p.fullyUnpacked())
377 {
378 return ipmi::responseReqDataLenInvalid();
379 }
380
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700381 // Send this request to the Redfish hooks to log it as a Redfish message
382 // instead. There is no need to add it to the SEL, so just return success.
383 intel_oem::ipmi::sel::checkRedfishHooks(
384 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
385 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700386
James Feist7aaf3fe2019-06-25 11:52:11 -0700387 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
388 eventData3)
389 {
390 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
391 }
392
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700393 return ipmi::responseSuccess();
394}
395
James Feist0cd014a2019-04-08 15:04:33 -0700396ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
397 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700398{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700399 std::string connection;
400 std::string path;
401
402 auto status = getSensorConnection(sensnum, connection, path);
403 if (status)
404 {
James Feist0cd014a2019-04-08 15:04:33 -0700405 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700406 }
407
408 SensorMap sensorMap;
409 if (!getSensorMap(connection, path, sensorMap))
410 {
James Feist0cd014a2019-04-08 15:04:33 -0700411 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700412 }
413 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
414
415 if (sensorObject == sensorMap.end() ||
416 sensorObject->second.find("Value") == sensorObject->second.end())
417 {
James Feist0cd014a2019-04-08 15:04:33 -0700418 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700419 }
James Feist0cd014a2019-04-08 15:04:33 -0700420 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700421 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700422
Yong Li1f2eb5e2019-05-23 14:07:17 +0800423 double max = 0;
424 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700425 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700426
427 int16_t mValue = 0;
428 int16_t bValue = 0;
429 int8_t rExp = 0;
430 int8_t bExp = 0;
431 bool bSigned = false;
432
433 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
434 {
James Feist0cd014a2019-04-08 15:04:33 -0700435 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700436 }
437
James Feist0cd014a2019-04-08 15:04:33 -0700438 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700439 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700440 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700441 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700442 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800443 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700444
James Feist0cd014a2019-04-08 15:04:33 -0700445 uint8_t thresholds = 0;
446
447 auto warningObject =
448 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
449 if (warningObject != sensorMap.end())
450 {
451 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
452 auto alarmLow = warningObject->second.find("WarningAlarmLow");
453 if (alarmHigh != warningObject->second.end())
454 {
455 if (std::get<bool>(alarmHigh->second))
456 {
457 thresholds |= static_cast<uint8_t>(
458 IPMISensorReadingByte3::upperNonCritical);
459 }
460 }
461 if (alarmLow != warningObject->second.end())
462 {
463 if (std::get<bool>(alarmLow->second))
464 {
465 thresholds |= static_cast<uint8_t>(
466 IPMISensorReadingByte3::lowerNonCritical);
467 }
468 }
469 }
470
471 auto criticalObject =
472 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
473 if (criticalObject != sensorMap.end())
474 {
475 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
476 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
477 if (alarmHigh != criticalObject->second.end())
478 {
479 if (std::get<bool>(alarmHigh->second))
480 {
481 thresholds |=
482 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
483 }
484 }
485 if (alarmLow != criticalObject->second.end())
486 {
487 if (std::get<bool>(alarmLow->second))
488 {
489 thresholds |=
490 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
491 }
492 }
493 }
494
495 // no discrete as of today so optional byte is never returned
496 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700497}
498
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000499/** @brief implements the Set Sensor threshold command
500 * @param sensorNumber - sensor number
501 * @param lowerNonCriticalThreshMask
502 * @param lowerCriticalThreshMask
503 * @param lowerNonRecovThreshMask
504 * @param upperNonCriticalThreshMask
505 * @param upperCriticalThreshMask
506 * @param upperNonRecovThreshMask
507 * @param reserved
508 * @param lowerNonCritical - lower non-critical threshold
509 * @param lowerCritical - Lower critical threshold
510 * @param lowerNonRecoverable - Lower non recovarable threshold
511 * @param upperNonCritical - Upper non-critical threshold
512 * @param upperCritical - Upper critical
513 * @param upperNonRecoverable - Upper Non-recoverable
514 *
515 * @returns IPMI completion code
516 */
517ipmi::RspType<> ipmiSenSetSensorThresholds(
518 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
519 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
520 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
521 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
522 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
523 uint8_t upperNonCritical, uint8_t upperCritical,
524 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700525{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000526 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700527
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000528 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700529 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000530 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700531 }
532
533 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000534 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700535 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000536 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700537 }
538
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000539 // if none of the threshold mask are set, nothing to do
540 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
541 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
542 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700543 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000544 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700545 }
546
547 std::string connection;
548 std::string path;
549
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000550 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700551 if (status)
552 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000553 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700554 }
555 SensorMap sensorMap;
556 if (!getSensorMap(connection, path, sensorMap))
557 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000558 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700559 }
560
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700561 double max = 0;
562 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700563 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700564
565 int16_t mValue = 0;
566 int16_t bValue = 0;
567 int8_t rExp = 0;
568 int8_t bExp = 0;
569 bool bSigned = false;
570
571 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
572 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000573 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700574 }
575
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700576 // store a vector of property name, value to set, and interface
577 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
578
579 // define the indexes of the tuple
580 constexpr uint8_t propertyName = 0;
581 constexpr uint8_t thresholdValue = 1;
582 constexpr uint8_t interface = 2;
583 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000584 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700585 {
586 auto findThreshold =
587 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
588 if (findThreshold == sensorMap.end())
589 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000590 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700591 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000592 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700593 {
594 auto findLower = findThreshold->second.find("CriticalLow");
595 if (findLower == findThreshold->second.end())
596 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000597 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700598 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000599 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700600 findThreshold->first);
601 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000602 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700603 {
604 auto findUpper = findThreshold->second.find("CriticalHigh");
605 if (findUpper == 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("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700610 findThreshold->first);
611 }
612 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000613 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700614 {
615 auto findThreshold =
616 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
617 if (findThreshold == sensorMap.end())
618 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000619 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000621 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700622 {
623 auto findLower = findThreshold->second.find("WarningLow");
624 if (findLower == findThreshold->second.end())
625 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000626 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700627 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000628 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700629 findThreshold->first);
630 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000631 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700632 {
633 auto findUpper = findThreshold->second.find("WarningHigh");
634 if (findUpper == 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("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700639 findThreshold->first);
640 }
641 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700642 for (const auto &property : thresholdsToSet)
643 {
644 // from section 36.3 in the IPMI Spec, assume all linear
645 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
646 (bValue * std::pow(10, bExp))) *
647 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700648 setDbusProperty(
649 *getSdBus(), connection, path, std::get<interface>(property),
650 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700651 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000652 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700653}
654
James Feist902c4c52019-04-16 14:51:31 -0700655IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700656{
James Feist902c4c52019-04-16 14:51:31 -0700657 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700658 auto warningInterface =
659 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
660 auto criticalInterface =
661 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
662
663 if ((warningInterface != sensorMap.end()) ||
664 (criticalInterface != sensorMap.end()))
665 {
666 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
667
668 if (sensorPair == sensorMap.end())
669 {
670 // should not have been able to find a sensor not implementing
671 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700672 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700673 }
674
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800675 double max = 0;
676 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700677 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700678
679 int16_t mValue = 0;
680 int16_t bValue = 0;
681 int8_t rExp = 0;
682 int8_t bExp = 0;
683 bool bSigned = false;
684
685 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
686 {
James Feist902c4c52019-04-16 14:51:31 -0700687 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700688 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700689 if (warningInterface != sensorMap.end())
690 {
691 auto &warningMap = warningInterface->second;
692
693 auto warningHigh = warningMap.find("WarningHigh");
694 auto warningLow = warningMap.find("WarningLow");
695
696 if (warningHigh != warningMap.end())
697 {
James Feist902c4c52019-04-16 14:51:31 -0700698
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700699 double value =
700 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700701 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700702 value, mValue, rExp, bValue, bExp, bSigned);
703 }
704 if (warningLow != warningMap.end())
705 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700706 double value =
707 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700708 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700709 value, mValue, rExp, bValue, bExp, bSigned);
710 }
711 }
712 if (criticalInterface != sensorMap.end())
713 {
714 auto &criticalMap = criticalInterface->second;
715
716 auto criticalHigh = criticalMap.find("CriticalHigh");
717 auto criticalLow = criticalMap.find("CriticalLow");
718
719 if (criticalHigh != criticalMap.end())
720 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700721 double value =
722 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700723 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700724 value, mValue, rExp, bValue, bExp, bSigned);
725 }
726 if (criticalLow != criticalMap.end())
727 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700728 double value =
729 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700730 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700731 value, mValue, rExp, bValue, bExp, bSigned);
732 }
733 }
734 }
James Feist902c4c52019-04-16 14:51:31 -0700735 return resp;
736}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700737
James Feist902c4c52019-04-16 14:51:31 -0700738ipmi::RspType<uint8_t, // readable
739 uint8_t, // lowerNCrit
740 uint8_t, // lowerCrit
741 uint8_t, // lowerNrecoverable
742 uint8_t, // upperNC
743 uint8_t, // upperCrit
744 uint8_t> // upperNRecoverable
745 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
746{
747 std::string connection;
748 std::string path;
749
750 auto status = getSensorConnection(sensorNumber, connection, path);
751 if (status)
752 {
753 return ipmi::response(status);
754 }
755
756 SensorMap sensorMap;
757 if (!getSensorMap(connection, path, sensorMap))
758 {
759 return ipmi::responseResponseError();
760 }
761
762 IPMIThresholds thresholdData;
763 try
764 {
765 thresholdData = getIPMIThresholds(sensorMap);
766 }
767 catch (std::exception &)
768 {
769 return ipmi::responseResponseError();
770 }
771
772 uint8_t readable = 0;
773 uint8_t lowerNC = 0;
774 uint8_t lowerCritical = 0;
775 uint8_t lowerNonRecoverable = 0;
776 uint8_t upperNC = 0;
777 uint8_t upperCritical = 0;
778 uint8_t upperNonRecoverable = 0;
779
780 if (thresholdData.warningHigh)
781 {
782 readable |=
783 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
784 upperNC = *thresholdData.warningHigh;
785 }
786 if (thresholdData.warningLow)
787 {
788 readable |=
789 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
790 lowerNC = *thresholdData.warningLow;
791 }
792
793 if (thresholdData.criticalHigh)
794 {
795 readable |=
796 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
797 upperCritical = *thresholdData.criticalHigh;
798 }
799 if (thresholdData.criticalLow)
800 {
801 readable |=
802 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
803 lowerCritical = *thresholdData.criticalLow;
804 }
805
806 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
807 lowerNonRecoverable, upperNC, upperCritical,
808 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700809}
810
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000811/** @brief implements the get Sensor event enable command
812 * @param sensorNumber - sensor number
813 *
814 * @returns IPMI completion code plus response data
815 * - enabled - Sensor Event messages
816 * - assertionEnabledLsb - Assertion event messages
817 * - assertionEnabledMsb - Assertion event messages
818 * - deassertionEnabledLsb - Deassertion event messages
819 * - deassertionEnabledMsb - Deassertion event messages
820 */
821
822ipmi::RspType<uint8_t, // enabled
823 uint8_t, // assertionEnabledLsb
824 uint8_t, // assertionEnabledMsb
825 uint8_t, // deassertionEnabledLsb
826 uint8_t> // deassertionEnabledMsb
827 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700828{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700829 std::string connection;
830 std::string path;
831
Patrick Venturea41714c2019-09-25 16:59:41 -0700832 uint8_t enabled = 0;
833 uint8_t assertionEnabledLsb = 0;
834 uint8_t assertionEnabledMsb = 0;
835 uint8_t deassertionEnabledLsb = 0;
836 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000837
838 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700839 if (status)
840 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000841 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700842 }
843
844 SensorMap sensorMap;
845 if (!getSensorMap(connection, path, sensorMap))
846 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000847 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700848 }
849
850 auto warningInterface =
851 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
852 auto criticalInterface =
853 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700854 if ((warningInterface != sensorMap.end()) ||
855 (criticalInterface != sensorMap.end()))
856 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000857 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700858 IPMISensorEventEnableByte2::sensorScanningEnable);
859 if (warningInterface != sensorMap.end())
860 {
861 auto &warningMap = warningInterface->second;
862
863 auto warningHigh = warningMap.find("WarningHigh");
864 auto warningLow = warningMap.find("WarningLow");
865 if (warningHigh != warningMap.end())
866 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000867 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700868 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000869 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700870 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
871 }
872 if (warningLow != warningMap.end())
873 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000874 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700875 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000876 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700877 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
878 }
879 }
880 if (criticalInterface != sensorMap.end())
881 {
882 auto &criticalMap = criticalInterface->second;
883
884 auto criticalHigh = criticalMap.find("CriticalHigh");
885 auto criticalLow = criticalMap.find("CriticalLow");
886
887 if (criticalHigh != criticalMap.end())
888 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000889 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700890 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000891 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700892 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
893 }
894 if (criticalLow != criticalMap.end())
895 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000896 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700897 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000898 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700899 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
900 }
901 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700902 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000903
904 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
905 assertionEnabledMsb, deassertionEnabledLsb,
906 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700907}
908
909ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
910 ipmi_request_t request,
911 ipmi_response_t response,
912 ipmi_data_len_t dataLen,
913 ipmi_context_t context)
914{
915 if (*dataLen != 1)
916 {
917 *dataLen = 0;
918 return IPMI_CC_REQ_DATA_LEN_INVALID;
919 }
920 *dataLen = 0; // default to 0 in case of an error
921
922 uint8_t sensnum = *(static_cast<uint8_t *>(request));
923
924 std::string connection;
925 std::string path;
926
927 auto status = getSensorConnection(sensnum, connection, path);
928 if (status)
929 {
930 return status;
931 }
932
933 SensorMap sensorMap;
934 if (!getSensorMap(connection, path, sensorMap))
935 {
936 return IPMI_CC_RESPONSE_ERROR;
937 }
938
939 auto warningInterface =
940 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
941 auto criticalInterface =
942 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
943
944 // zero out response buff
945 auto responseClear = static_cast<uint8_t *>(response);
946 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
947 auto resp = static_cast<SensorEventStatusResp *>(response);
948 resp->enabled =
949 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
950
James Feist392786a2019-03-19 13:36:10 -0700951 std::optional<bool> criticalDeassertHigh =
952 thresholdDeassertMap[path]["CriticalAlarmHigh"];
953 std::optional<bool> criticalDeassertLow =
954 thresholdDeassertMap[path]["CriticalAlarmLow"];
955 std::optional<bool> warningDeassertHigh =
956 thresholdDeassertMap[path]["WarningAlarmHigh"];
957 std::optional<bool> warningDeassertLow =
958 thresholdDeassertMap[path]["WarningAlarmLow"];
959
960 if (criticalDeassertHigh && !*criticalDeassertHigh)
961 {
962 resp->deassertionsMSB |= static_cast<uint8_t>(
963 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
964 }
965 if (criticalDeassertLow && !*criticalDeassertLow)
966 {
967 resp->deassertionsMSB |= static_cast<uint8_t>(
968 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
969 }
970 if (warningDeassertHigh && !*warningDeassertHigh)
971 {
972 resp->deassertionsLSB |= static_cast<uint8_t>(
973 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
974 }
975 if (warningDeassertLow && !*warningDeassertLow)
976 {
977 resp->deassertionsLSB |= static_cast<uint8_t>(
978 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
979 }
980
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700981 if ((warningInterface != sensorMap.end()) ||
982 (criticalInterface != sensorMap.end()))
983 {
984 resp->enabled = static_cast<uint8_t>(
985 IPMISensorEventEnableByte2::eventMessagesEnable);
986 if (warningInterface != sensorMap.end())
987 {
988 auto &warningMap = warningInterface->second;
989
990 auto warningHigh = warningMap.find("WarningAlarmHigh");
991 auto warningLow = warningMap.find("WarningAlarmLow");
992 auto warningHighAlarm = false;
993 auto warningLowAlarm = false;
994
995 if (warningHigh != warningMap.end())
996 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700997 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700998 }
999 if (warningLow != warningMap.end())
1000 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001001 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001002 }
1003 if (warningHighAlarm)
1004 {
1005 resp->assertionsLSB |= static_cast<uint8_t>(
1006 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1007 }
1008 if (warningLowAlarm)
1009 {
1010 resp->assertionsLSB |= 1; // lower nc going low
1011 }
1012 }
1013 if (criticalInterface != sensorMap.end())
1014 {
1015 auto &criticalMap = criticalInterface->second;
1016
1017 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1018 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1019 auto criticalHighAlarm = false;
1020 auto criticalLowAlarm = false;
1021
1022 if (criticalHigh != criticalMap.end())
1023 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001024 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001025 }
1026 if (criticalLow != criticalMap.end())
1027 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001028 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001029 }
1030 if (criticalHighAlarm)
1031 {
1032 resp->assertionsMSB |= static_cast<uint8_t>(
1033 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1034 }
1035 if (criticalLowAlarm)
1036 {
1037 resp->assertionsLSB |= static_cast<uint8_t>(
1038 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1039 }
1040 }
1041 *dataLen = sizeof(SensorEventStatusResp);
1042 }
1043
1044 // no thresholds enabled, don't need assertionMSB
1045 else
1046 {
1047 *dataLen = sizeof(SensorEventStatusResp) - 1;
1048 }
1049
1050 return IPMI_CC_OK;
1051}
1052
1053/* end sensor commands */
1054
1055/* storage commands */
1056
James Feist74c50c62019-08-14 14:18:41 -07001057ipmi::RspType<uint8_t, // sdr version
1058 uint16_t, // record count
1059 uint16_t, // free space
1060 uint32_t, // most recent addition
1061 uint32_t, // most recent erase
1062 uint8_t // operationSupport
1063 >
1064 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001065{
James Feist74c50c62019-08-14 14:18:41 -07001066 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001067 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1068 {
James Feist74c50c62019-08-14 14:18:41 -07001069 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001070 }
1071
James Feist74c50c62019-08-14 14:18:41 -07001072 size_t fruCount = 0;
1073 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1074 if (ret != ipmi::ccSuccess)
1075 {
1076 return ipmi::response(ret);
1077 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001078
James Feist74c50c62019-08-14 14:18:41 -07001079 uint16_t recordCount =
1080 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001081
James Feist74c50c62019-08-14 14:18:41 -07001082 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001083 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001084
1085 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001086 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001087 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001088 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001089 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1090 unspecifiedFreeSpace, sdrLastAdd,
1091 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001092}
1093
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001094/** @brief implements the get SDR allocation info command
1095 *
1096 * @returns IPMI completion code plus response data
1097 * - allocUnits - Number of possible allocation units
1098 * - allocUnitSize - Allocation unit size in bytes.
1099 * - allocUnitFree - Number of free allocation units
1100 * - allocUnitLargestFree - Largest free block in allocation units
1101 * - maxRecordSize - Maximum record size in allocation units.
1102 */
1103ipmi::RspType<uint16_t, // allocUnits
1104 uint16_t, // allocUnitSize
1105 uint16_t, // allocUnitFree
1106 uint16_t, // allocUnitLargestFree
1107 uint8_t // maxRecordSize
1108 >
1109 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001110{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001111 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001112 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001113
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001114 constexpr uint16_t allocUnitFree = 0;
1115 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001116 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001117 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001119 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1120 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001121}
1122
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001123/** @brief implements the reserve SDR command
1124 * @returns IPMI completion code plus response data
1125 * - sdrReservationID
1126 */
1127ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001128{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001129 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001130 if (sdrReservationID == 0)
1131 {
1132 sdrReservationID++;
1133 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001134
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001135 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001136}
1137
James Feistb49a98a2019-04-16 13:48:09 -07001138ipmi::RspType<uint16_t, // next record ID
1139 std::vector<uint8_t> // payload
1140 >
1141 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1142 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001143{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001144 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001145
1146 // reservation required for partial reads with non zero offset into
1147 // record
James Feistb49a98a2019-04-16 13:48:09 -07001148 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001149 {
James Feistb49a98a2019-04-16 13:48:09 -07001150 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001151 }
1152
1153 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1154 {
James Feistb49a98a2019-04-16 13:48:09 -07001155 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001156 }
1157
1158 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001159 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1160 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001161 {
James Feistb49a98a2019-04-16 13:48:09 -07001162 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001163 }
1164
James Feist74c50c62019-08-14 14:18:41 -07001165 size_t lastRecord =
1166 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001167 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001168 {
James Feistb49a98a2019-04-16 13:48:09 -07001169 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001170 }
James Feistb49a98a2019-04-16 13:48:09 -07001171 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001172 {
James Feistb49a98a2019-04-16 13:48:09 -07001173 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001174 }
1175
James Feistb49a98a2019-04-16 13:48:09 -07001176 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001177
James Feistb49a98a2019-04-16 13:48:09 -07001178 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001179 {
James Feist74c50c62019-08-14 14:18:41 -07001180 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001181 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001182 if (fruIndex >= fruCount)
1183 {
James Feist74c50c62019-08-14 14:18:41 -07001184 // handle type 12 hardcoded records
1185 size_t type12Index = fruIndex - fruCount;
1186 if (type12Index >= ipmi::storage::type12Count ||
1187 offset > sizeof(Type12Record))
1188 {
1189 return ipmi::responseInvalidFieldRequest();
1190 }
1191 std::vector<uint8_t> record =
1192 ipmi::storage::getType12SDRs(type12Index, recordID);
1193 if (record.size() < (offset + bytesToRead))
1194 {
1195 bytesToRead = record.size() - offset;
1196 }
James Feistb49a98a2019-04-16 13:48:09 -07001197
James Feist74c50c62019-08-14 14:18:41 -07001198 recordData.insert(recordData.end(), record.begin() + offset,
1199 record.begin() + offset + bytesToRead);
1200 }
1201 else
1202 {
1203 // handle fru records
1204 get_sdr::SensorDataFruRecord data;
1205 if (offset > sizeof(data))
1206 {
1207 return ipmi::responseInvalidFieldRequest();
1208 }
1209 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1210 if (ret != IPMI_CC_OK)
1211 {
1212 return ipmi::response(ret);
1213 }
1214 data.header.record_id_msb = recordID << 8;
1215 data.header.record_id_lsb = recordID & 0xFF;
1216 if (sizeof(data) < (offset + bytesToRead))
1217 {
1218 bytesToRead = sizeof(data) - offset;
1219 }
1220
1221 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1222 recordData.insert(recordData.end(), respStart,
1223 respStart + bytesToRead);
1224 }
James Feistb49a98a2019-04-16 13:48:09 -07001225
1226 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001227 }
1228
1229 std::string connection;
1230 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001231 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001232 for (const auto &sensor : sensorTree)
1233 {
1234 if (sensorIndex-- == 0)
1235 {
1236 if (!sensor.second.size())
1237 {
James Feistb49a98a2019-04-16 13:48:09 -07001238 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001239 }
1240 connection = sensor.second.begin()->first;
1241 path = sensor.first;
1242 break;
1243 }
1244 }
1245
1246 SensorMap sensorMap;
1247 if (!getSensorMap(connection, path, sensorMap))
1248 {
James Feistb49a98a2019-04-16 13:48:09 -07001249 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001250 }
James Feistb49a98a2019-04-16 13:48:09 -07001251 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001252 get_sdr::SensorDataFullRecord record = {0};
1253
James Feistb49a98a2019-04-16 13:48:09 -07001254 record.header.record_id_msb = recordID << 8;
1255 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001256 record.header.sdr_version = ipmiSdrVersion;
1257 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1258 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1259 sizeof(get_sdr::SensorDataRecordHeader);
1260 record.key.owner_id = 0x20;
1261 record.key.owner_lun = 0x0;
1262 record.key.sensor_number = sensornumber;
1263
1264 record.body.entity_id = 0x0;
1265 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001266 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001267 record.body.sensor_type = getSensorTypeFromPath(path);
1268 std::string type = getSensorTypeStringFromPath(path);
1269 auto typeCstr = type.c_str();
1270 auto findUnits = sensorUnits.find(typeCstr);
1271 if (findUnits != sensorUnits.end())
1272 {
1273 record.body.sensor_units_2_base =
1274 static_cast<uint8_t>(findUnits->second);
1275 } // else default 0x0 unspecified
1276
1277 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1278
1279 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1280 if (sensorObject == sensorMap.end())
1281 {
James Feistb49a98a2019-04-16 13:48:09 -07001282 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001283 }
1284
1285 auto maxObject = sensorObject->second.find("MaxValue");
1286 auto minObject = sensorObject->second.find("MinValue");
1287 double max = 128;
1288 double min = -127;
1289 if (maxObject != sensorObject->second.end())
1290 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001291 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001292 }
1293
1294 if (minObject != sensorObject->second.end())
1295 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001296 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001297 }
1298
Yong Li1f2eb5e2019-05-23 14:07:17 +08001299 int16_t mValue = 0;
1300 int8_t rExp = 0;
1301 int16_t bValue = 0;
1302 int8_t bExp = 0;
1303 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001304
1305 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1306 {
James Feistb49a98a2019-04-16 13:48:09 -07001307 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001308 }
1309
1310 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1311 record.body.m_lsb = mValue & 0xFF;
1312
1313 // move the smallest bit of the MSB into place (bit 9)
1314 // the MSbs are bits 7:8 in m_msb_and_tolerance
1315 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1316
1317 // assign the negative
1318 if (mValue < 0)
1319 {
1320 mMsb |= (1 << 7);
1321 }
1322 record.body.m_msb_and_tolerance = mMsb;
1323
1324 record.body.b_lsb = bValue & 0xFF;
1325
1326 // move the smallest bit of the MSB into place
1327 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1328 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1329
1330 // assign the negative
1331 if (bValue < 0)
1332 {
1333 bMsb |= (1 << 7);
1334 }
1335 record.body.b_msb_and_accuracy_lsb = bMsb;
1336
1337 record.body.r_b_exponents = bExp & 0x7;
1338 if (bExp < 0)
1339 {
1340 record.body.r_b_exponents |= 1 << 3;
1341 }
1342 record.body.r_b_exponents = (rExp & 0x7) << 4;
1343 if (rExp < 0)
1344 {
1345 record.body.r_b_exponents |= 1 << 7;
1346 }
1347
1348 // todo fill out rest of units
1349 if (bSigned)
1350 {
1351 record.body.sensor_units_1 = 1 << 7;
1352 }
1353
1354 // populate sensor name from path
1355 std::string name;
1356 size_t nameStart = path.rfind("/");
1357 if (nameStart != std::string::npos)
1358 {
1359 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1360 }
1361
1362 std::replace(name.begin(), name.end(), '_', ' ');
1363 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1364 {
James Feist979a2322019-05-15 09:06:54 -07001365 // try to not truncate by replacing common words
1366 constexpr std::array<std::pair<const char *, const char *>, 2>
1367 replaceWords = {std::make_pair("Output", "Out"),
1368 std::make_pair("Input", "In")};
1369 for (const auto &[find, replace] : replaceWords)
1370 {
1371 boost::replace_all(name, find, replace);
1372 }
1373
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001374 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1375 }
1376 record.body.id_string_info = name.size();
1377 std::strncpy(record.body.id_string, name.c_str(),
1378 sizeof(record.body.id_string));
1379
James Feistc4b15bc2019-04-16 15:41:39 -07001380 IPMIThresholds thresholdData;
1381 try
1382 {
1383 thresholdData = getIPMIThresholds(sensorMap);
1384 }
1385 catch (std::exception &)
1386 {
1387 return ipmi::responseResponseError();
1388 }
1389
1390 if (thresholdData.criticalHigh)
1391 {
1392 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1393 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1394 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1395 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1396 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1397 record.body.discrete_reading_setting_mask[0] |=
1398 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1399 }
1400 if (thresholdData.warningHigh)
1401 {
1402 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1403 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1404 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1405 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1406 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1407 record.body.discrete_reading_setting_mask[0] |=
1408 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1409 }
1410 if (thresholdData.criticalLow)
1411 {
1412 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1413 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1414 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1415 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1416 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1417 record.body.discrete_reading_setting_mask[0] |=
1418 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1419 }
1420 if (thresholdData.warningLow)
1421 {
1422 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1423 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1424 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1425 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1426 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1427 record.body.discrete_reading_setting_mask[0] |=
1428 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1429 }
1430
1431 // everything that is readable is setable
1432 record.body.discrete_reading_setting_mask[1] =
1433 record.body.discrete_reading_setting_mask[0];
1434
James Feistb49a98a2019-04-16 13:48:09 -07001435 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001436 {
James Feistb49a98a2019-04-16 13:48:09 -07001437 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001438 }
1439
James Feistb49a98a2019-04-16 13:48:09 -07001440 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1441 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001442
James Feistb49a98a2019-04-16 13:48:09 -07001443 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001444}
1445/* end storage commands */
1446
1447void registerSensorFunctions()
1448{
1449 // get firmware version information
1450 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1451 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1452
1453 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001454 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1455 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001456
1457 // <Set Sensor Reading and Event Status>
1458 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001459 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001460 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1461
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001462 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001463 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1464 ipmi::sensor_event::cmdPlatformEvent,
1465 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001466
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001467 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001468 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1469 ipmi::sensor_event::cmdGetSensorReading,
1470 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001471
1472 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001473 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1474 ipmi::sensor_event::cmdGetSensorThreshold,
1475 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001476
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001477 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001478 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1479 ipmi::sensor_event::cmdSetSensorThreshold,
1480 ipmi::Privilege::Operator,
1481 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001482
1483 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001484 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1485 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001486 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001487
1488 // <Get Sensor Event Status>
1489 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001490 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1491 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001492
1493 // register all storage commands for both Sensor and Storage command
1494 // versions
1495
1496 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001497 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1498 ipmi::storage::cmdGetSdrRepositoryInfo,
1499 ipmi::Privilege::User,
1500 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001501
1502 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001503 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1504 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1505 ipmi::Privilege::User,
1506 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001507
1508 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001509 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1510 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001511 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001512
Vernon Mauery98bbf692019-09-16 11:14:59 -07001513 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1514 ipmi::storage::cmdReserveSdrRepository,
1515 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001516
1517 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001518 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1519 ipmi::sensor_event::cmdGetDeviceSdr,
1520 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001521
Vernon Mauery98bbf692019-09-16 11:14:59 -07001522 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1523 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1524 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001525}
1526} // namespace ipmi