blob: 764efe7a44724eb06423ce183408a0dbb8de69f2 [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>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070026#include <phosphor-logging/log.hpp>
27#include <sdbusplus/bus.hpp>
28#include <sdrutils.hpp>
29#include <sensorcommands.hpp>
30#include <sensorutils.hpp>
31#include <storagecommands.hpp>
32#include <string>
33
34namespace ipmi
35{
36using ManagedObjectType =
37 std::map<sdbusplus::message::object_path,
38 std::map<std::string, std::map<std::string, DbusVariant>>>;
39
40using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
41
42static constexpr int sensorListUpdatePeriod = 10;
43static constexpr int sensorMapUpdatePeriod = 2;
44
45constexpr size_t maxSDRTotalSize =
46 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
47constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
48
49static uint16_t sdrReservationID;
50static uint32_t sdrLastAdd = noTimestamp;
51static uint32_t sdrLastRemove = noTimestamp;
52
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053053SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070054static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
55
Jason M. Bills17add592018-11-12 14:30:12 -080056// Specify the comparison required to sort and find char* map objects
57struct CmpStr
58{
59 bool operator()(const char *a, const char *b) const
60 {
61 return std::strcmp(a, b) < 0;
62 }
63};
64const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
65 sensorUnits{{{"temperature", SensorUnits::degreesC},
66 {"voltage", SensorUnits::volts},
67 {"current", SensorUnits::amps},
68 {"fan_tach", SensorUnits::rpm},
69 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070070
71void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070072
73static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070074 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070075 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
76 "sensors/'",
77 [](sdbusplus::message::message &m) {
78 sensorTree.clear();
79 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
80 std::chrono::system_clock::now().time_since_epoch())
81 .count();
82 });
83
84static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070085 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070086 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
87 "sensors/'",
88 [](sdbusplus::message::message &m) {
89 sensorTree.clear();
90 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
91 std::chrono::system_clock::now().time_since_epoch())
92 .count();
93 });
94
James Feist392786a2019-03-19 13:36:10 -070095// this keeps track of deassertions for sensor event status command. A
96// deasertion can only happen if an assertion was seen first.
97static boost::container::flat_map<
98 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
99 thresholdDeassertMap;
100
101static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700102 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700103 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
104 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
105 [](sdbusplus::message::message &m) {
106 boost::container::flat_map<std::string, std::variant<bool, double>>
107 values;
108 m.read(std::string(), values);
109
110 auto findAssert =
111 std::find_if(values.begin(), values.end(), [](const auto &pair) {
112 return pair.first.find("Alarm") != std::string::npos;
113 });
114 if (findAssert != values.end())
115 {
116 auto ptr = std::get_if<bool>(&(findAssert->second));
117 if (ptr == nullptr)
118 {
119 phosphor::logging::log<phosphor::logging::level::ERR>(
120 "thresholdChanged: Assert non bool");
121 return;
122 }
123 if (*ptr)
124 {
125 phosphor::logging::log<phosphor::logging::level::INFO>(
126 "thresholdChanged: Assert",
127 phosphor::logging::entry("SENSOR=%s", m.get_path()));
128 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
129 }
130 else
131 {
132 auto &value =
133 thresholdDeassertMap[m.get_path()][findAssert->first];
134 if (value)
135 {
136 phosphor::logging::log<phosphor::logging::level::INFO>(
137 "thresholdChanged: deassert",
138 phosphor::logging::entry("SENSOR=%s", m.get_path()));
139 value = *ptr;
140 }
141 }
142 }
143 });
144
James Feistaecaef72019-04-26 10:30:32 -0700145static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
146 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700147{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700148 max = 127;
149 min = -128;
150
James Feistaecaef72019-04-26 10:30:32 -0700151 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
152 auto critical =
153 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
154 auto warning =
155 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
156
157 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700158 {
James Feistaecaef72019-04-26 10:30:32 -0700159 auto maxMap = sensorObject->second.find("MaxValue");
160 auto minMap = sensorObject->second.find("MinValue");
161
162 if (maxMap != sensorObject->second.end())
163 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700164 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700165 }
166 if (minMap != sensorObject->second.end())
167 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700168 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700169 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700170 }
James Feistaecaef72019-04-26 10:30:32 -0700171 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700172 {
James Feistaecaef72019-04-26 10:30:32 -0700173 auto lower = critical->second.find("CriticalLow");
174 auto upper = critical->second.find("CriticalHigh");
175 if (lower != critical->second.end())
176 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700177 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700178 min = std::min(value, min);
179 }
180 if (upper != critical->second.end())
181 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700182 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700183 max = std::max(value, max);
184 }
185 }
186 if (warning != sensorMap.end())
187 {
188
189 auto lower = warning->second.find("WarningLow");
190 auto upper = warning->second.find("WarningHigh");
191 if (lower != warning->second.end())
192 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700193 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700194 min = std::min(value, min);
195 }
196 if (upper != warning->second.end())
197 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700198 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700199 max = std::max(value, max);
200 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700201 }
202}
203
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700204static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
205 SensorMap &sensorMap)
206{
207 static boost::container::flat_map<
208 std::string, std::chrono::time_point<std::chrono::steady_clock>>
209 updateTimeMap;
210
211 auto updateFind = updateTimeMap.find(sensorConnection);
212 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
213 if (updateFind != updateTimeMap.end())
214 {
215 lastUpdate = updateFind->second;
216 }
217
218 auto now = std::chrono::steady_clock::now();
219
220 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
221 .count() > sensorMapUpdatePeriod)
222 {
223 updateTimeMap[sensorConnection] = now;
224
Vernon Mauery15419dd2019-05-24 09:40:30 -0700225 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
226 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700227 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
228 "GetManagedObjects");
229
230 ManagedObjectType managedObjects;
231 try
232 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700233 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700234 reply.read(managedObjects);
235 }
236 catch (sdbusplus::exception_t &)
237 {
238 phosphor::logging::log<phosphor::logging::level::ERR>(
239 "Error getting managed objects from connection",
240 phosphor::logging::entry("CONNECTION=%s",
241 sensorConnection.c_str()));
242 return false;
243 }
244
245 SensorCache[sensorConnection] = managedObjects;
246 }
247 auto connection = SensorCache.find(sensorConnection);
248 if (connection == SensorCache.end())
249 {
250 return false;
251 }
252 auto path = connection->second.find(sensorPath);
253 if (path == connection->second.end())
254 {
255 return false;
256 }
257 sensorMap = path->second;
258
259 return true;
260}
261
262/* sensor commands */
263ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
264 ipmi_request_t request,
265 ipmi_response_t response,
266 ipmi_data_len_t dataLen,
267 ipmi_context_t context)
268{
269 *dataLen = 0;
270 printCommand(+netfn, +cmd);
271 return IPMI_CC_INVALID;
272}
273
James Feist7aaf3fe2019-06-25 11:52:11 -0700274namespace meHealth
275{
276constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
277constexpr const char *path = "/xyz/openbmc_project/status/me";
278constexpr const char *interface = "xyz.openbmc_project.SetHealth";
279constexpr const char *method = "SetHealth";
280constexpr const char *critical = "critical";
281constexpr const char *warning = "warning";
282constexpr const char *ok = "ok";
283} // namespace meHealth
284
285static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
286{
287 constexpr const std::array<uint8_t, 10> critical = {
288 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
289 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
290 0x1A};
291
292 std::string state;
293 if (std::find(critical.begin(), critical.end(), eventData2) !=
294 critical.end())
295 {
296 state = meHealth::critical;
297 }
298 // special case 0x3 as we only care about a few states
299 else if (eventData2 == 0x3)
300 {
301 if (eventData3 <= 0x2)
302 {
303 state = meHealth::warning;
304 }
305 else
306 {
307 return;
308 }
309 }
310 else if (std::find(warning.begin(), warning.end(), eventData2) !=
311 warning.end())
312 {
313 state = meHealth::warning;
314 }
315 else
316 {
317 return;
318 }
319 if (disable)
320 {
321 state = meHealth::ok;
322 }
323
324 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
325 auto setHealth =
326 dbus->new_method_call(meHealth::busname, meHealth::path,
327 meHealth::interface, meHealth::method);
328 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
329 try
330 {
331 dbus->call(setHealth);
332 }
333 catch (sdbusplus::exception_t &)
334 {
335 phosphor::logging::log<phosphor::logging::level::ERR>(
336 "Failed to set ME Health");
337 }
338}
339
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700340ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
341{
James Feist7aaf3fe2019-06-25 11:52:11 -0700342 constexpr const uint8_t meId = 0x2C;
343 constexpr const uint8_t meSensorNum = 0x17;
344 constexpr const uint8_t disabled = 0x80;
345
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700346 uint8_t generatorID = 0;
347 uint8_t evmRev = 0;
348 uint8_t sensorType = 0;
349 uint8_t sensorNum = 0;
350 uint8_t eventType = 0;
351 uint8_t eventData1 = 0;
352 std::optional<uint8_t> eventData2 = 0;
353 std::optional<uint8_t> eventData3 = 0;
354
355 // todo: This check is supposed to be based on the incoming channel.
356 // e.g. system channel will provide upto 8 bytes including generator
357 // ID, but ipmb channel will provide only up to 7 bytes without the
358 // generator ID.
359 // Support for this check is coming in future patches, so for now just base
360 // it on if the first byte is the EvMRev (0x04).
361 if (p.size() && p.data()[0] == 0x04)
362 {
363 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
364 eventData2, eventData3);
365 // todo: the generator ID for this channel is supposed to come from the
366 // IPMB requesters slave address. Support for this is coming in future
367 // patches, so for now just assume it is coming from the ME (0x2C).
368 generatorID = 0x2C;
369 }
370 else
371 {
372 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
373 eventData1, eventData2, eventData3);
374 }
375 if (!p.fullyUnpacked())
376 {
377 return ipmi::responseReqDataLenInvalid();
378 }
379
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700380 // Send this request to the Redfish hooks to log it as a Redfish message
381 // instead. There is no need to add it to the SEL, so just return success.
382 intel_oem::ipmi::sel::checkRedfishHooks(
383 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
384 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700385
James Feist7aaf3fe2019-06-25 11:52:11 -0700386 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
387 eventData3)
388 {
389 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
390 }
391
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700392 return ipmi::responseSuccess();
393}
394
James Feist0cd014a2019-04-08 15:04:33 -0700395ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
396 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700397{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700398 std::string connection;
399 std::string path;
400
401 auto status = getSensorConnection(sensnum, connection, path);
402 if (status)
403 {
James Feist0cd014a2019-04-08 15:04:33 -0700404 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700405 }
406
407 SensorMap sensorMap;
408 if (!getSensorMap(connection, path, sensorMap))
409 {
James Feist0cd014a2019-04-08 15:04:33 -0700410 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700411 }
412 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
413
414 if (sensorObject == sensorMap.end() ||
415 sensorObject->second.find("Value") == sensorObject->second.end())
416 {
James Feist0cd014a2019-04-08 15:04:33 -0700417 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700418 }
James Feist0cd014a2019-04-08 15:04:33 -0700419 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700420 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700421
Yong Li1f2eb5e2019-05-23 14:07:17 +0800422 double max = 0;
423 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700424 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700425
426 int16_t mValue = 0;
427 int16_t bValue = 0;
428 int8_t rExp = 0;
429 int8_t bExp = 0;
430 bool bSigned = false;
431
432 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
433 {
James Feist0cd014a2019-04-08 15:04:33 -0700434 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700435 }
436
James Feist0cd014a2019-04-08 15:04:33 -0700437 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700438 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700439 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700440 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700441 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800442 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700443
James Feist0cd014a2019-04-08 15:04:33 -0700444 uint8_t thresholds = 0;
445
446 auto warningObject =
447 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
448 if (warningObject != sensorMap.end())
449 {
450 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
451 auto alarmLow = warningObject->second.find("WarningAlarmLow");
452 if (alarmHigh != warningObject->second.end())
453 {
454 if (std::get<bool>(alarmHigh->second))
455 {
456 thresholds |= static_cast<uint8_t>(
457 IPMISensorReadingByte3::upperNonCritical);
458 }
459 }
460 if (alarmLow != warningObject->second.end())
461 {
462 if (std::get<bool>(alarmLow->second))
463 {
464 thresholds |= static_cast<uint8_t>(
465 IPMISensorReadingByte3::lowerNonCritical);
466 }
467 }
468 }
469
470 auto criticalObject =
471 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
472 if (criticalObject != sensorMap.end())
473 {
474 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
475 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
476 if (alarmHigh != criticalObject->second.end())
477 {
478 if (std::get<bool>(alarmHigh->second))
479 {
480 thresholds |=
481 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
482 }
483 }
484 if (alarmLow != criticalObject->second.end())
485 {
486 if (std::get<bool>(alarmLow->second))
487 {
488 thresholds |=
489 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
490 }
491 }
492 }
493
494 // no discrete as of today so optional byte is never returned
495 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700496}
497
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000498/** @brief implements the Set Sensor threshold command
499 * @param sensorNumber - sensor number
500 * @param lowerNonCriticalThreshMask
501 * @param lowerCriticalThreshMask
502 * @param lowerNonRecovThreshMask
503 * @param upperNonCriticalThreshMask
504 * @param upperCriticalThreshMask
505 * @param upperNonRecovThreshMask
506 * @param reserved
507 * @param lowerNonCritical - lower non-critical threshold
508 * @param lowerCritical - Lower critical threshold
509 * @param lowerNonRecoverable - Lower non recovarable threshold
510 * @param upperNonCritical - Upper non-critical threshold
511 * @param upperCritical - Upper critical
512 * @param upperNonRecoverable - Upper Non-recoverable
513 *
514 * @returns IPMI completion code
515 */
516ipmi::RspType<> ipmiSenSetSensorThresholds(
517 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
518 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
519 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
520 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
521 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
522 uint8_t upperNonCritical, uint8_t upperCritical,
523 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700524{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000525 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700526
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000527 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700528 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000529 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700530 }
531
532 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000533 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700534 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000535 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700536 }
537
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000538 // if none of the threshold mask are set, nothing to do
539 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
540 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
541 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700542 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000543 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700544 }
545
546 std::string connection;
547 std::string path;
548
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000549 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700550 if (status)
551 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000552 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700553 }
554 SensorMap sensorMap;
555 if (!getSensorMap(connection, path, sensorMap))
556 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000557 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700558 }
559
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700560 double max = 0;
561 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700562 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700563
564 int16_t mValue = 0;
565 int16_t bValue = 0;
566 int8_t rExp = 0;
567 int8_t bExp = 0;
568 bool bSigned = false;
569
570 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
571 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000572 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700573 }
574
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700575 // store a vector of property name, value to set, and interface
576 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
577
578 // define the indexes of the tuple
579 constexpr uint8_t propertyName = 0;
580 constexpr uint8_t thresholdValue = 1;
581 constexpr uint8_t interface = 2;
582 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000583 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700584 {
585 auto findThreshold =
586 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
587 if (findThreshold == sensorMap.end())
588 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000589 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700590 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000591 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700592 {
593 auto findLower = findThreshold->second.find("CriticalLow");
594 if (findLower == findThreshold->second.end())
595 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000596 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700597 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000598 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700599 findThreshold->first);
600 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000601 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700602 {
603 auto findUpper = findThreshold->second.find("CriticalHigh");
604 if (findUpper == findThreshold->second.end())
605 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000606 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700607 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000608 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700609 findThreshold->first);
610 }
611 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000612 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700613 {
614 auto findThreshold =
615 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
616 if (findThreshold == sensorMap.end())
617 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000618 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700619 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000620 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700621 {
622 auto findLower = findThreshold->second.find("WarningLow");
623 if (findLower == findThreshold->second.end())
624 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000625 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700626 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 findThreshold->first);
629 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 {
632 auto findUpper = findThreshold->second.find("WarningHigh");
633 if (findUpper == findThreshold->second.end())
634 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000635 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700636 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000637 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700638 findThreshold->first);
639 }
640 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700641 for (const auto &property : thresholdsToSet)
642 {
643 // from section 36.3 in the IPMI Spec, assume all linear
644 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
645 (bValue * std::pow(10, bExp))) *
646 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700647 setDbusProperty(
648 *getSdBus(), connection, path, std::get<interface>(property),
649 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000651 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700652}
653
James Feist902c4c52019-04-16 14:51:31 -0700654IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700655{
James Feist902c4c52019-04-16 14:51:31 -0700656 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700657 auto warningInterface =
658 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
659 auto criticalInterface =
660 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
661
662 if ((warningInterface != sensorMap.end()) ||
663 (criticalInterface != sensorMap.end()))
664 {
665 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
666
667 if (sensorPair == sensorMap.end())
668 {
669 // should not have been able to find a sensor not implementing
670 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700671 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700672 }
673
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800674 double max = 0;
675 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700676 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700677
678 int16_t mValue = 0;
679 int16_t bValue = 0;
680 int8_t rExp = 0;
681 int8_t bExp = 0;
682 bool bSigned = false;
683
684 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
685 {
James Feist902c4c52019-04-16 14:51:31 -0700686 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700687 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700688 if (warningInterface != sensorMap.end())
689 {
690 auto &warningMap = warningInterface->second;
691
692 auto warningHigh = warningMap.find("WarningHigh");
693 auto warningLow = warningMap.find("WarningLow");
694
695 if (warningHigh != warningMap.end())
696 {
James Feist902c4c52019-04-16 14:51:31 -0700697
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700698 double value =
699 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700700 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700701 value, mValue, rExp, bValue, bExp, bSigned);
702 }
703 if (warningLow != warningMap.end())
704 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700705 double value =
706 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700707 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700708 value, mValue, rExp, bValue, bExp, bSigned);
709 }
710 }
711 if (criticalInterface != sensorMap.end())
712 {
713 auto &criticalMap = criticalInterface->second;
714
715 auto criticalHigh = criticalMap.find("CriticalHigh");
716 auto criticalLow = criticalMap.find("CriticalLow");
717
718 if (criticalHigh != criticalMap.end())
719 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700720 double value =
721 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700722 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700723 value, mValue, rExp, bValue, bExp, bSigned);
724 }
725 if (criticalLow != criticalMap.end())
726 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700727 double value =
728 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700729 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700730 value, mValue, rExp, bValue, bExp, bSigned);
731 }
732 }
733 }
James Feist902c4c52019-04-16 14:51:31 -0700734 return resp;
735}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700736
James Feist902c4c52019-04-16 14:51:31 -0700737ipmi::RspType<uint8_t, // readable
738 uint8_t, // lowerNCrit
739 uint8_t, // lowerCrit
740 uint8_t, // lowerNrecoverable
741 uint8_t, // upperNC
742 uint8_t, // upperCrit
743 uint8_t> // upperNRecoverable
744 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
745{
746 std::string connection;
747 std::string path;
748
749 auto status = getSensorConnection(sensorNumber, connection, path);
750 if (status)
751 {
752 return ipmi::response(status);
753 }
754
755 SensorMap sensorMap;
756 if (!getSensorMap(connection, path, sensorMap))
757 {
758 return ipmi::responseResponseError();
759 }
760
761 IPMIThresholds thresholdData;
762 try
763 {
764 thresholdData = getIPMIThresholds(sensorMap);
765 }
766 catch (std::exception &)
767 {
768 return ipmi::responseResponseError();
769 }
770
771 uint8_t readable = 0;
772 uint8_t lowerNC = 0;
773 uint8_t lowerCritical = 0;
774 uint8_t lowerNonRecoverable = 0;
775 uint8_t upperNC = 0;
776 uint8_t upperCritical = 0;
777 uint8_t upperNonRecoverable = 0;
778
779 if (thresholdData.warningHigh)
780 {
781 readable |=
782 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
783 upperNC = *thresholdData.warningHigh;
784 }
785 if (thresholdData.warningLow)
786 {
787 readable |=
788 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
789 lowerNC = *thresholdData.warningLow;
790 }
791
792 if (thresholdData.criticalHigh)
793 {
794 readable |=
795 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
796 upperCritical = *thresholdData.criticalHigh;
797 }
798 if (thresholdData.criticalLow)
799 {
800 readable |=
801 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
802 lowerCritical = *thresholdData.criticalLow;
803 }
804
805 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
806 lowerNonRecoverable, upperNC, upperCritical,
807 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700808}
809
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000810/** @brief implements the get Sensor event enable command
811 * @param sensorNumber - sensor number
812 *
813 * @returns IPMI completion code plus response data
814 * - enabled - Sensor Event messages
815 * - assertionEnabledLsb - Assertion event messages
816 * - assertionEnabledMsb - Assertion event messages
817 * - deassertionEnabledLsb - Deassertion event messages
818 * - deassertionEnabledMsb - Deassertion event messages
819 */
820
821ipmi::RspType<uint8_t, // enabled
822 uint8_t, // assertionEnabledLsb
823 uint8_t, // assertionEnabledMsb
824 uint8_t, // deassertionEnabledLsb
825 uint8_t> // deassertionEnabledMsb
826 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700827{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700828 std::string connection;
829 std::string path;
830
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000831 uint8_t enabled;
832 uint8_t assertionEnabledLsb;
833 uint8_t assertionEnabledMsb;
834 uint8_t deassertionEnabledLsb;
835 uint8_t deassertionEnabledMsb;
836
837 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700838 if (status)
839 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000840 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700841 }
842
843 SensorMap sensorMap;
844 if (!getSensorMap(connection, path, sensorMap))
845 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000846 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700847 }
848
849 auto warningInterface =
850 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
851 auto criticalInterface =
852 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700853 if ((warningInterface != sensorMap.end()) ||
854 (criticalInterface != sensorMap.end()))
855 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000856 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700857 IPMISensorEventEnableByte2::sensorScanningEnable);
858 if (warningInterface != sensorMap.end())
859 {
860 auto &warningMap = warningInterface->second;
861
862 auto warningHigh = warningMap.find("WarningHigh");
863 auto warningLow = warningMap.find("WarningLow");
864 if (warningHigh != warningMap.end())
865 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000866 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700867 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000868 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700869 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
870 }
871 if (warningLow != warningMap.end())
872 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000873 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700874 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000875 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700876 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
877 }
878 }
879 if (criticalInterface != sensorMap.end())
880 {
881 auto &criticalMap = criticalInterface->second;
882
883 auto criticalHigh = criticalMap.find("CriticalHigh");
884 auto criticalLow = criticalMap.find("CriticalLow");
885
886 if (criticalHigh != criticalMap.end())
887 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000888 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700889 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000890 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700891 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
892 }
893 if (criticalLow != criticalMap.end())
894 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000895 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700896 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000897 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700898 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
899 }
900 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700901 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000902
903 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
904 assertionEnabledMsb, deassertionEnabledLsb,
905 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700906}
907
908ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
909 ipmi_request_t request,
910 ipmi_response_t response,
911 ipmi_data_len_t dataLen,
912 ipmi_context_t context)
913{
914 if (*dataLen != 1)
915 {
916 *dataLen = 0;
917 return IPMI_CC_REQ_DATA_LEN_INVALID;
918 }
919 *dataLen = 0; // default to 0 in case of an error
920
921 uint8_t sensnum = *(static_cast<uint8_t *>(request));
922
923 std::string connection;
924 std::string path;
925
926 auto status = getSensorConnection(sensnum, connection, path);
927 if (status)
928 {
929 return status;
930 }
931
932 SensorMap sensorMap;
933 if (!getSensorMap(connection, path, sensorMap))
934 {
935 return IPMI_CC_RESPONSE_ERROR;
936 }
937
938 auto warningInterface =
939 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
940 auto criticalInterface =
941 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
942
943 // zero out response buff
944 auto responseClear = static_cast<uint8_t *>(response);
945 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
946 auto resp = static_cast<SensorEventStatusResp *>(response);
947 resp->enabled =
948 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
949
James Feist392786a2019-03-19 13:36:10 -0700950 std::optional<bool> criticalDeassertHigh =
951 thresholdDeassertMap[path]["CriticalAlarmHigh"];
952 std::optional<bool> criticalDeassertLow =
953 thresholdDeassertMap[path]["CriticalAlarmLow"];
954 std::optional<bool> warningDeassertHigh =
955 thresholdDeassertMap[path]["WarningAlarmHigh"];
956 std::optional<bool> warningDeassertLow =
957 thresholdDeassertMap[path]["WarningAlarmLow"];
958
959 if (criticalDeassertHigh && !*criticalDeassertHigh)
960 {
961 resp->deassertionsMSB |= static_cast<uint8_t>(
962 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
963 }
964 if (criticalDeassertLow && !*criticalDeassertLow)
965 {
966 resp->deassertionsMSB |= static_cast<uint8_t>(
967 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
968 }
969 if (warningDeassertHigh && !*warningDeassertHigh)
970 {
971 resp->deassertionsLSB |= static_cast<uint8_t>(
972 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
973 }
974 if (warningDeassertLow && !*warningDeassertLow)
975 {
976 resp->deassertionsLSB |= static_cast<uint8_t>(
977 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
978 }
979
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700980 if ((warningInterface != sensorMap.end()) ||
981 (criticalInterface != sensorMap.end()))
982 {
983 resp->enabled = static_cast<uint8_t>(
984 IPMISensorEventEnableByte2::eventMessagesEnable);
985 if (warningInterface != sensorMap.end())
986 {
987 auto &warningMap = warningInterface->second;
988
989 auto warningHigh = warningMap.find("WarningAlarmHigh");
990 auto warningLow = warningMap.find("WarningAlarmLow");
991 auto warningHighAlarm = false;
992 auto warningLowAlarm = false;
993
994 if (warningHigh != warningMap.end())
995 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700996 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700997 }
998 if (warningLow != warningMap.end())
999 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001000 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001001 }
1002 if (warningHighAlarm)
1003 {
1004 resp->assertionsLSB |= static_cast<uint8_t>(
1005 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1006 }
1007 if (warningLowAlarm)
1008 {
1009 resp->assertionsLSB |= 1; // lower nc going low
1010 }
1011 }
1012 if (criticalInterface != sensorMap.end())
1013 {
1014 auto &criticalMap = criticalInterface->second;
1015
1016 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1017 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1018 auto criticalHighAlarm = false;
1019 auto criticalLowAlarm = false;
1020
1021 if (criticalHigh != criticalMap.end())
1022 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001023 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001024 }
1025 if (criticalLow != criticalMap.end())
1026 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001027 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001028 }
1029 if (criticalHighAlarm)
1030 {
1031 resp->assertionsMSB |= static_cast<uint8_t>(
1032 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1033 }
1034 if (criticalLowAlarm)
1035 {
1036 resp->assertionsLSB |= static_cast<uint8_t>(
1037 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1038 }
1039 }
1040 *dataLen = sizeof(SensorEventStatusResp);
1041 }
1042
1043 // no thresholds enabled, don't need assertionMSB
1044 else
1045 {
1046 *dataLen = sizeof(SensorEventStatusResp) - 1;
1047 }
1048
1049 return IPMI_CC_OK;
1050}
1051
1052/* end sensor commands */
1053
1054/* storage commands */
1055
James Feist74c50c62019-08-14 14:18:41 -07001056ipmi::RspType<uint8_t, // sdr version
1057 uint16_t, // record count
1058 uint16_t, // free space
1059 uint32_t, // most recent addition
1060 uint32_t, // most recent erase
1061 uint8_t // operationSupport
1062 >
1063 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001064{
James Feist74c50c62019-08-14 14:18:41 -07001065 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001066 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1067 {
James Feist74c50c62019-08-14 14:18:41 -07001068 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001069 }
1070
James Feist74c50c62019-08-14 14:18:41 -07001071 size_t fruCount = 0;
1072 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1073 if (ret != ipmi::ccSuccess)
1074 {
1075 return ipmi::response(ret);
1076 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001077
James Feist74c50c62019-08-14 14:18:41 -07001078 uint16_t recordCount =
1079 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001080
James Feist74c50c62019-08-14 14:18:41 -07001081 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001082 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001083
1084 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001085 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001086 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001087 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001088 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1089 unspecifiedFreeSpace, sdrLastAdd,
1090 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001091}
1092
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001093/** @brief implements the get SDR allocation info command
1094 *
1095 * @returns IPMI completion code plus response data
1096 * - allocUnits - Number of possible allocation units
1097 * - allocUnitSize - Allocation unit size in bytes.
1098 * - allocUnitFree - Number of free allocation units
1099 * - allocUnitLargestFree - Largest free block in allocation units
1100 * - maxRecordSize - Maximum record size in allocation units.
1101 */
1102ipmi::RspType<uint16_t, // allocUnits
1103 uint16_t, // allocUnitSize
1104 uint16_t, // allocUnitFree
1105 uint16_t, // allocUnitLargestFree
1106 uint8_t // maxRecordSize
1107 >
1108 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001109{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001110 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001111 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001112
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001113 constexpr uint16_t allocUnitFree = 0;
1114 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001115 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001116 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001117
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001118 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1119 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120}
1121
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001122/** @brief implements the reserve SDR command
1123 * @returns IPMI completion code plus response data
1124 * - sdrReservationID
1125 */
1126ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001127{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001128 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001129 if (sdrReservationID == 0)
1130 {
1131 sdrReservationID++;
1132 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001133
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001134 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001135}
1136
James Feistb49a98a2019-04-16 13:48:09 -07001137ipmi::RspType<uint16_t, // next record ID
1138 std::vector<uint8_t> // payload
1139 >
1140 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1141 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001142{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001143 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001144
1145 // reservation required for partial reads with non zero offset into
1146 // record
James Feistb49a98a2019-04-16 13:48:09 -07001147 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001148 {
James Feistb49a98a2019-04-16 13:48:09 -07001149 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001150 }
1151
1152 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1153 {
James Feistb49a98a2019-04-16 13:48:09 -07001154 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001155 }
1156
1157 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001158 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1159 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001160 {
James Feistb49a98a2019-04-16 13:48:09 -07001161 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001162 }
1163
James Feist74c50c62019-08-14 14:18:41 -07001164 size_t lastRecord =
1165 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001166 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167 {
James Feistb49a98a2019-04-16 13:48:09 -07001168 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001169 }
James Feistb49a98a2019-04-16 13:48:09 -07001170 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001171 {
James Feistb49a98a2019-04-16 13:48:09 -07001172 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173 }
1174
James Feistb49a98a2019-04-16 13:48:09 -07001175 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001176
James Feistb49a98a2019-04-16 13:48:09 -07001177 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001178 {
James Feist74c50c62019-08-14 14:18:41 -07001179 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001180 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001181 if (fruIndex >= fruCount)
1182 {
James Feist74c50c62019-08-14 14:18:41 -07001183 // handle type 12 hardcoded records
1184 size_t type12Index = fruIndex - fruCount;
1185 if (type12Index >= ipmi::storage::type12Count ||
1186 offset > sizeof(Type12Record))
1187 {
1188 return ipmi::responseInvalidFieldRequest();
1189 }
1190 std::vector<uint8_t> record =
1191 ipmi::storage::getType12SDRs(type12Index, recordID);
1192 if (record.size() < (offset + bytesToRead))
1193 {
1194 bytesToRead = record.size() - offset;
1195 }
James Feistb49a98a2019-04-16 13:48:09 -07001196
James Feist74c50c62019-08-14 14:18:41 -07001197 recordData.insert(recordData.end(), record.begin() + offset,
1198 record.begin() + offset + bytesToRead);
1199 }
1200 else
1201 {
1202 // handle fru records
1203 get_sdr::SensorDataFruRecord data;
1204 if (offset > sizeof(data))
1205 {
1206 return ipmi::responseInvalidFieldRequest();
1207 }
1208 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1209 if (ret != IPMI_CC_OK)
1210 {
1211 return ipmi::response(ret);
1212 }
1213 data.header.record_id_msb = recordID << 8;
1214 data.header.record_id_lsb = recordID & 0xFF;
1215 if (sizeof(data) < (offset + bytesToRead))
1216 {
1217 bytesToRead = sizeof(data) - offset;
1218 }
1219
1220 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1221 recordData.insert(recordData.end(), respStart,
1222 respStart + bytesToRead);
1223 }
James Feistb49a98a2019-04-16 13:48:09 -07001224
1225 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001226 }
1227
1228 std::string connection;
1229 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001230 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001231 for (const auto &sensor : sensorTree)
1232 {
1233 if (sensorIndex-- == 0)
1234 {
1235 if (!sensor.second.size())
1236 {
James Feistb49a98a2019-04-16 13:48:09 -07001237 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001238 }
1239 connection = sensor.second.begin()->first;
1240 path = sensor.first;
1241 break;
1242 }
1243 }
1244
1245 SensorMap sensorMap;
1246 if (!getSensorMap(connection, path, sensorMap))
1247 {
James Feistb49a98a2019-04-16 13:48:09 -07001248 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001249 }
James Feistb49a98a2019-04-16 13:48:09 -07001250 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001251 get_sdr::SensorDataFullRecord record = {0};
1252
James Feistb49a98a2019-04-16 13:48:09 -07001253 record.header.record_id_msb = recordID << 8;
1254 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001255 record.header.sdr_version = ipmiSdrVersion;
1256 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1257 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1258 sizeof(get_sdr::SensorDataRecordHeader);
1259 record.key.owner_id = 0x20;
1260 record.key.owner_lun = 0x0;
1261 record.key.sensor_number = sensornumber;
1262
1263 record.body.entity_id = 0x0;
1264 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001265 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001266 record.body.sensor_type = getSensorTypeFromPath(path);
1267 std::string type = getSensorTypeStringFromPath(path);
1268 auto typeCstr = type.c_str();
1269 auto findUnits = sensorUnits.find(typeCstr);
1270 if (findUnits != sensorUnits.end())
1271 {
1272 record.body.sensor_units_2_base =
1273 static_cast<uint8_t>(findUnits->second);
1274 } // else default 0x0 unspecified
1275
1276 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1277
1278 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1279 if (sensorObject == sensorMap.end())
1280 {
James Feistb49a98a2019-04-16 13:48:09 -07001281 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001282 }
1283
1284 auto maxObject = sensorObject->second.find("MaxValue");
1285 auto minObject = sensorObject->second.find("MinValue");
1286 double max = 128;
1287 double min = -127;
1288 if (maxObject != sensorObject->second.end())
1289 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001290 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001291 }
1292
1293 if (minObject != sensorObject->second.end())
1294 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001295 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001296 }
1297
Yong Li1f2eb5e2019-05-23 14:07:17 +08001298 int16_t mValue = 0;
1299 int8_t rExp = 0;
1300 int16_t bValue = 0;
1301 int8_t bExp = 0;
1302 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001303
1304 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1305 {
James Feistb49a98a2019-04-16 13:48:09 -07001306 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001307 }
1308
1309 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1310 record.body.m_lsb = mValue & 0xFF;
1311
1312 // move the smallest bit of the MSB into place (bit 9)
1313 // the MSbs are bits 7:8 in m_msb_and_tolerance
1314 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1315
1316 // assign the negative
1317 if (mValue < 0)
1318 {
1319 mMsb |= (1 << 7);
1320 }
1321 record.body.m_msb_and_tolerance = mMsb;
1322
1323 record.body.b_lsb = bValue & 0xFF;
1324
1325 // move the smallest bit of the MSB into place
1326 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1327 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1328
1329 // assign the negative
1330 if (bValue < 0)
1331 {
1332 bMsb |= (1 << 7);
1333 }
1334 record.body.b_msb_and_accuracy_lsb = bMsb;
1335
1336 record.body.r_b_exponents = bExp & 0x7;
1337 if (bExp < 0)
1338 {
1339 record.body.r_b_exponents |= 1 << 3;
1340 }
1341 record.body.r_b_exponents = (rExp & 0x7) << 4;
1342 if (rExp < 0)
1343 {
1344 record.body.r_b_exponents |= 1 << 7;
1345 }
1346
1347 // todo fill out rest of units
1348 if (bSigned)
1349 {
1350 record.body.sensor_units_1 = 1 << 7;
1351 }
1352
1353 // populate sensor name from path
1354 std::string name;
1355 size_t nameStart = path.rfind("/");
1356 if (nameStart != std::string::npos)
1357 {
1358 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1359 }
1360
1361 std::replace(name.begin(), name.end(), '_', ' ');
1362 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1363 {
James Feist979a2322019-05-15 09:06:54 -07001364 // try to not truncate by replacing common words
1365 constexpr std::array<std::pair<const char *, const char *>, 2>
1366 replaceWords = {std::make_pair("Output", "Out"),
1367 std::make_pair("Input", "In")};
1368 for (const auto &[find, replace] : replaceWords)
1369 {
1370 boost::replace_all(name, find, replace);
1371 }
1372
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001373 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1374 }
1375 record.body.id_string_info = name.size();
1376 std::strncpy(record.body.id_string, name.c_str(),
1377 sizeof(record.body.id_string));
1378
James Feistc4b15bc2019-04-16 15:41:39 -07001379 IPMIThresholds thresholdData;
1380 try
1381 {
1382 thresholdData = getIPMIThresholds(sensorMap);
1383 }
1384 catch (std::exception &)
1385 {
1386 return ipmi::responseResponseError();
1387 }
1388
1389 if (thresholdData.criticalHigh)
1390 {
1391 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1392 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1393 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1394 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1395 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1396 record.body.discrete_reading_setting_mask[0] |=
1397 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1398 }
1399 if (thresholdData.warningHigh)
1400 {
1401 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1402 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1403 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1404 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1405 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1406 record.body.discrete_reading_setting_mask[0] |=
1407 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1408 }
1409 if (thresholdData.criticalLow)
1410 {
1411 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1412 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1413 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1414 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1415 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1416 record.body.discrete_reading_setting_mask[0] |=
1417 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1418 }
1419 if (thresholdData.warningLow)
1420 {
1421 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1422 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1423 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1424 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1425 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1426 record.body.discrete_reading_setting_mask[0] |=
1427 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1428 }
1429
1430 // everything that is readable is setable
1431 record.body.discrete_reading_setting_mask[1] =
1432 record.body.discrete_reading_setting_mask[0];
1433
James Feistb49a98a2019-04-16 13:48:09 -07001434 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001435 {
James Feistb49a98a2019-04-16 13:48:09 -07001436 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001437 }
1438
James Feistb49a98a2019-04-16 13:48:09 -07001439 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1440 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001441
James Feistb49a98a2019-04-16 13:48:09 -07001442 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001443}
1444/* end storage commands */
1445
1446void registerSensorFunctions()
1447{
1448 // get firmware version information
1449 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1450 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1451
1452 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001453 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1454 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001455
1456 // <Set Sensor Reading and Event Status>
1457 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001458 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001459 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1460
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001461 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001462 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1463 ipmi::sensor_event::cmdPlatformEvent,
1464 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001465
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001466 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001467 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1468 ipmi::sensor_event::cmdGetSensorReading,
1469 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001470
1471 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001472 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1473 ipmi::sensor_event::cmdGetSensorThreshold,
1474 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001475
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001476 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001477 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1478 ipmi::sensor_event::cmdSetSensorThreshold,
1479 ipmi::Privilege::Operator,
1480 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001481
1482 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001483 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1484 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001485 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001486
1487 // <Get Sensor Event Status>
1488 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001489 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1490 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001491
1492 // register all storage commands for both Sensor and Storage command
1493 // versions
1494
1495 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001496 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1497 ipmi::storage::cmdGetSdrRepositoryInfo,
1498 ipmi::Privilege::User,
1499 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001500
1501 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001502 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1503 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1504 ipmi::Privilege::User,
1505 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001506
1507 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001508 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1509 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001510 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001511
Vernon Mauery98bbf692019-09-16 11:14:59 -07001512 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1513 ipmi::storage::cmdReserveSdrRepository,
1514 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001515
1516 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001517 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1518 ipmi::sensor_event::cmdGetDeviceSdr,
1519 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001520
Vernon Mauery98bbf692019-09-16 11:14:59 -07001521 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1522 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1523 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001524}
1525} // namespace ipmi