blob: effd0f5f9540d84e24c4089a5daa202875ec17a2 [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>
Patrick Venturec4e9de62019-09-25 17:40:54 -070027#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070028#include <phosphor-logging/log.hpp>
29#include <sdbusplus/bus.hpp>
30#include <sdrutils.hpp>
31#include <sensorcommands.hpp>
32#include <sensorutils.hpp>
33#include <storagecommands.hpp>
34#include <string>
35
36namespace ipmi
37{
38using ManagedObjectType =
39 std::map<sdbusplus::message::object_path,
40 std::map<std::string, std::map<std::string, DbusVariant>>>;
41
42using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
43
44static constexpr int sensorListUpdatePeriod = 10;
45static constexpr int sensorMapUpdatePeriod = 2;
46
47constexpr size_t maxSDRTotalSize =
48 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
49constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
50
51static uint16_t sdrReservationID;
52static uint32_t sdrLastAdd = noTimestamp;
53static uint32_t sdrLastRemove = noTimestamp;
54
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053055SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070056static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
57
Jason M. Bills17add592018-11-12 14:30:12 -080058// Specify the comparison required to sort and find char* map objects
59struct CmpStr
60{
61 bool operator()(const char *a, const char *b) const
62 {
63 return std::strcmp(a, b) < 0;
64 }
65};
66const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
67 sensorUnits{{{"temperature", SensorUnits::degreesC},
68 {"voltage", SensorUnits::volts},
69 {"current", SensorUnits::amps},
70 {"fan_tach", SensorUnits::rpm},
71 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070072
73void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070074
75static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070076 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070077 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
78 "sensors/'",
79 [](sdbusplus::message::message &m) {
80 sensorTree.clear();
81 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
82 std::chrono::system_clock::now().time_since_epoch())
83 .count();
84 });
85
86static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070087 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070088 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
89 "sensors/'",
90 [](sdbusplus::message::message &m) {
91 sensorTree.clear();
92 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
93 std::chrono::system_clock::now().time_since_epoch())
94 .count();
95 });
96
James Feist392786a2019-03-19 13:36:10 -070097// this keeps track of deassertions for sensor event status command. A
98// deasertion can only happen if an assertion was seen first.
99static boost::container::flat_map<
100 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
101 thresholdDeassertMap;
102
103static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700104 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700105 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
106 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
107 [](sdbusplus::message::message &m) {
108 boost::container::flat_map<std::string, std::variant<bool, double>>
109 values;
110 m.read(std::string(), values);
111
112 auto findAssert =
113 std::find_if(values.begin(), values.end(), [](const auto &pair) {
114 return pair.first.find("Alarm") != std::string::npos;
115 });
116 if (findAssert != values.end())
117 {
118 auto ptr = std::get_if<bool>(&(findAssert->second));
119 if (ptr == nullptr)
120 {
121 phosphor::logging::log<phosphor::logging::level::ERR>(
122 "thresholdChanged: Assert non bool");
123 return;
124 }
125 if (*ptr)
126 {
127 phosphor::logging::log<phosphor::logging::level::INFO>(
128 "thresholdChanged: Assert",
129 phosphor::logging::entry("SENSOR=%s", m.get_path()));
130 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
131 }
132 else
133 {
134 auto &value =
135 thresholdDeassertMap[m.get_path()][findAssert->first];
136 if (value)
137 {
138 phosphor::logging::log<phosphor::logging::level::INFO>(
139 "thresholdChanged: deassert",
140 phosphor::logging::entry("SENSOR=%s", m.get_path()));
141 value = *ptr;
142 }
143 }
144 }
145 });
146
James Feistaecaef72019-04-26 10:30:32 -0700147static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
148 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700149{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700150 max = 127;
151 min = -128;
152
James Feistaecaef72019-04-26 10:30:32 -0700153 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
154 auto critical =
155 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
156 auto warning =
157 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
158
159 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700160 {
James Feistaecaef72019-04-26 10:30:32 -0700161 auto maxMap = sensorObject->second.find("MaxValue");
162 auto minMap = sensorObject->second.find("MinValue");
163
164 if (maxMap != sensorObject->second.end())
165 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700166 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700167 }
168 if (minMap != sensorObject->second.end())
169 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700170 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700171 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700172 }
James Feistaecaef72019-04-26 10:30:32 -0700173 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700174 {
James Feistaecaef72019-04-26 10:30:32 -0700175 auto lower = critical->second.find("CriticalLow");
176 auto upper = critical->second.find("CriticalHigh");
177 if (lower != critical->second.end())
178 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700179 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700180 min = std::min(value, min);
181 }
182 if (upper != critical->second.end())
183 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700184 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700185 max = std::max(value, max);
186 }
187 }
188 if (warning != sensorMap.end())
189 {
190
191 auto lower = warning->second.find("WarningLow");
192 auto upper = warning->second.find("WarningHigh");
193 if (lower != warning->second.end())
194 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700195 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700196 min = std::min(value, min);
197 }
198 if (upper != warning->second.end())
199 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700200 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700201 max = std::max(value, max);
202 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700203 }
204}
205
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700206static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
207 SensorMap &sensorMap)
208{
209 static boost::container::flat_map<
210 std::string, std::chrono::time_point<std::chrono::steady_clock>>
211 updateTimeMap;
212
213 auto updateFind = updateTimeMap.find(sensorConnection);
214 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
215 if (updateFind != updateTimeMap.end())
216 {
217 lastUpdate = updateFind->second;
218 }
219
220 auto now = std::chrono::steady_clock::now();
221
222 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
223 .count() > sensorMapUpdatePeriod)
224 {
225 updateTimeMap[sensorConnection] = now;
226
Vernon Mauery15419dd2019-05-24 09:40:30 -0700227 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
228 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700229 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
230 "GetManagedObjects");
231
232 ManagedObjectType managedObjects;
233 try
234 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700235 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700236 reply.read(managedObjects);
237 }
238 catch (sdbusplus::exception_t &)
239 {
240 phosphor::logging::log<phosphor::logging::level::ERR>(
241 "Error getting managed objects from connection",
242 phosphor::logging::entry("CONNECTION=%s",
243 sensorConnection.c_str()));
244 return false;
245 }
246
247 SensorCache[sensorConnection] = managedObjects;
248 }
249 auto connection = SensorCache.find(sensorConnection);
250 if (connection == SensorCache.end())
251 {
252 return false;
253 }
254 auto path = connection->second.find(sensorPath);
255 if (path == connection->second.end())
256 {
257 return false;
258 }
259 sensorMap = path->second;
260
261 return true;
262}
263
264/* sensor commands */
265ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
266 ipmi_request_t request,
267 ipmi_response_t response,
268 ipmi_data_len_t dataLen,
269 ipmi_context_t context)
270{
271 *dataLen = 0;
272 printCommand(+netfn, +cmd);
273 return IPMI_CC_INVALID;
274}
275
James Feist7aaf3fe2019-06-25 11:52:11 -0700276namespace meHealth
277{
278constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
279constexpr const char *path = "/xyz/openbmc_project/status/me";
280constexpr const char *interface = "xyz.openbmc_project.SetHealth";
281constexpr const char *method = "SetHealth";
282constexpr const char *critical = "critical";
283constexpr const char *warning = "warning";
284constexpr const char *ok = "ok";
285} // namespace meHealth
286
287static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
288{
289 constexpr const std::array<uint8_t, 10> critical = {
290 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
291 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
292 0x1A};
293
294 std::string state;
295 if (std::find(critical.begin(), critical.end(), eventData2) !=
296 critical.end())
297 {
298 state = meHealth::critical;
299 }
300 // special case 0x3 as we only care about a few states
301 else if (eventData2 == 0x3)
302 {
303 if (eventData3 <= 0x2)
304 {
305 state = meHealth::warning;
306 }
307 else
308 {
309 return;
310 }
311 }
312 else if (std::find(warning.begin(), warning.end(), eventData2) !=
313 warning.end())
314 {
315 state = meHealth::warning;
316 }
317 else
318 {
319 return;
320 }
321 if (disable)
322 {
323 state = meHealth::ok;
324 }
325
326 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
327 auto setHealth =
328 dbus->new_method_call(meHealth::busname, meHealth::path,
329 meHealth::interface, meHealth::method);
330 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
331 try
332 {
333 dbus->call(setHealth);
334 }
335 catch (sdbusplus::exception_t &)
336 {
337 phosphor::logging::log<phosphor::logging::level::ERR>(
338 "Failed to set ME Health");
339 }
340}
341
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700342ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
343{
James Feist7aaf3fe2019-06-25 11:52:11 -0700344 constexpr const uint8_t meId = 0x2C;
345 constexpr const uint8_t meSensorNum = 0x17;
346 constexpr const uint8_t disabled = 0x80;
347
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700348 uint8_t generatorID = 0;
349 uint8_t evmRev = 0;
350 uint8_t sensorType = 0;
351 uint8_t sensorNum = 0;
352 uint8_t eventType = 0;
353 uint8_t eventData1 = 0;
354 std::optional<uint8_t> eventData2 = 0;
355 std::optional<uint8_t> eventData3 = 0;
356
357 // todo: This check is supposed to be based on the incoming channel.
358 // e.g. system channel will provide upto 8 bytes including generator
359 // ID, but ipmb channel will provide only up to 7 bytes without the
360 // generator ID.
361 // Support for this check is coming in future patches, so for now just base
362 // it on if the first byte is the EvMRev (0x04).
363 if (p.size() && p.data()[0] == 0x04)
364 {
365 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
366 eventData2, eventData3);
367 // todo: the generator ID for this channel is supposed to come from the
368 // IPMB requesters slave address. Support for this is coming in future
369 // patches, so for now just assume it is coming from the ME (0x2C).
370 generatorID = 0x2C;
371 }
372 else
373 {
374 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
375 eventData1, eventData2, eventData3);
376 }
377 if (!p.fullyUnpacked())
378 {
379 return ipmi::responseReqDataLenInvalid();
380 }
381
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700382 // Send this request to the Redfish hooks to log it as a Redfish message
383 // instead. There is no need to add it to the SEL, so just return success.
384 intel_oem::ipmi::sel::checkRedfishHooks(
385 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
386 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700387
James Feist7aaf3fe2019-06-25 11:52:11 -0700388 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
389 eventData3)
390 {
391 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
392 }
393
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700394 return ipmi::responseSuccess();
395}
396
James Feist0cd014a2019-04-08 15:04:33 -0700397ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
398 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700399{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700400 std::string connection;
401 std::string path;
402
403 auto status = getSensorConnection(sensnum, connection, path);
404 if (status)
405 {
James Feist0cd014a2019-04-08 15:04:33 -0700406 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700407 }
408
409 SensorMap sensorMap;
410 if (!getSensorMap(connection, path, sensorMap))
411 {
James Feist0cd014a2019-04-08 15:04:33 -0700412 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700413 }
414 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
415
416 if (sensorObject == sensorMap.end() ||
417 sensorObject->second.find("Value") == sensorObject->second.end())
418 {
James Feist0cd014a2019-04-08 15:04:33 -0700419 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700420 }
James Feist0cd014a2019-04-08 15:04:33 -0700421 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700422 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700423
Yong Li1f2eb5e2019-05-23 14:07:17 +0800424 double max = 0;
425 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700426 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700427
428 int16_t mValue = 0;
429 int16_t bValue = 0;
430 int8_t rExp = 0;
431 int8_t bExp = 0;
432 bool bSigned = false;
433
434 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
435 {
James Feist0cd014a2019-04-08 15:04:33 -0700436 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700437 }
438
James Feist0cd014a2019-04-08 15:04:33 -0700439 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700440 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700441 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700442 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700443 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800444 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700445
James Feist0cd014a2019-04-08 15:04:33 -0700446 uint8_t thresholds = 0;
447
448 auto warningObject =
449 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
450 if (warningObject != sensorMap.end())
451 {
452 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
453 auto alarmLow = warningObject->second.find("WarningAlarmLow");
454 if (alarmHigh != warningObject->second.end())
455 {
456 if (std::get<bool>(alarmHigh->second))
457 {
458 thresholds |= static_cast<uint8_t>(
459 IPMISensorReadingByte3::upperNonCritical);
460 }
461 }
462 if (alarmLow != warningObject->second.end())
463 {
464 if (std::get<bool>(alarmLow->second))
465 {
466 thresholds |= static_cast<uint8_t>(
467 IPMISensorReadingByte3::lowerNonCritical);
468 }
469 }
470 }
471
472 auto criticalObject =
473 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
474 if (criticalObject != sensorMap.end())
475 {
476 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
477 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
478 if (alarmHigh != criticalObject->second.end())
479 {
480 if (std::get<bool>(alarmHigh->second))
481 {
482 thresholds |=
483 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
484 }
485 }
486 if (alarmLow != criticalObject->second.end())
487 {
488 if (std::get<bool>(alarmLow->second))
489 {
490 thresholds |=
491 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
492 }
493 }
494 }
495
496 // no discrete as of today so optional byte is never returned
497 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700498}
499
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000500/** @brief implements the Set Sensor threshold command
501 * @param sensorNumber - sensor number
502 * @param lowerNonCriticalThreshMask
503 * @param lowerCriticalThreshMask
504 * @param lowerNonRecovThreshMask
505 * @param upperNonCriticalThreshMask
506 * @param upperCriticalThreshMask
507 * @param upperNonRecovThreshMask
508 * @param reserved
509 * @param lowerNonCritical - lower non-critical threshold
510 * @param lowerCritical - Lower critical threshold
511 * @param lowerNonRecoverable - Lower non recovarable threshold
512 * @param upperNonCritical - Upper non-critical threshold
513 * @param upperCritical - Upper critical
514 * @param upperNonRecoverable - Upper Non-recoverable
515 *
516 * @returns IPMI completion code
517 */
518ipmi::RspType<> ipmiSenSetSensorThresholds(
519 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
520 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
521 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
522 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
523 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
524 uint8_t upperNonCritical, uint8_t upperCritical,
525 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700526{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000527 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700528
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000529 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700530 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000531 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700532 }
533
534 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000535 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700536 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000537 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700538 }
539
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000540 // if none of the threshold mask are set, nothing to do
541 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
542 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
543 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700544 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000545 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700546 }
547
548 std::string connection;
549 std::string path;
550
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000551 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700552 if (status)
553 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000554 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700555 }
556 SensorMap sensorMap;
557 if (!getSensorMap(connection, path, sensorMap))
558 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000559 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700560 }
561
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700562 double max = 0;
563 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700564 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700565
566 int16_t mValue = 0;
567 int16_t bValue = 0;
568 int8_t rExp = 0;
569 int8_t bExp = 0;
570 bool bSigned = false;
571
572 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
573 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000574 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700575 }
576
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700577 // store a vector of property name, value to set, and interface
578 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
579
580 // define the indexes of the tuple
581 constexpr uint8_t propertyName = 0;
582 constexpr uint8_t thresholdValue = 1;
583 constexpr uint8_t interface = 2;
584 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000585 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700586 {
587 auto findThreshold =
588 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
589 if (findThreshold == sensorMap.end())
590 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000591 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700592 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000593 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700594 {
595 auto findLower = findThreshold->second.find("CriticalLow");
596 if (findLower == findThreshold->second.end())
597 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000598 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700599 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000600 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700601 findThreshold->first);
602 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000603 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700604 {
605 auto findUpper = findThreshold->second.find("CriticalHigh");
606 if (findUpper == findThreshold->second.end())
607 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000608 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700609 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000610 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700611 findThreshold->first);
612 }
613 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000614 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700615 {
616 auto findThreshold =
617 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
618 if (findThreshold == sensorMap.end())
619 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000620 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700621 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000622 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700623 {
624 auto findLower = findThreshold->second.find("WarningLow");
625 if (findLower == findThreshold->second.end())
626 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000629 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700630 findThreshold->first);
631 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000632 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700633 {
634 auto findUpper = findThreshold->second.find("WarningHigh");
635 if (findUpper == findThreshold->second.end())
636 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000637 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700638 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000639 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700640 findThreshold->first);
641 }
642 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700643 for (const auto &property : thresholdsToSet)
644 {
645 // from section 36.3 in the IPMI Spec, assume all linear
646 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
647 (bValue * std::pow(10, bExp))) *
648 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700649 setDbusProperty(
650 *getSdBus(), connection, path, std::get<interface>(property),
651 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700652 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000653 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700654}
655
James Feist902c4c52019-04-16 14:51:31 -0700656IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700657{
James Feist902c4c52019-04-16 14:51:31 -0700658 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700659 auto warningInterface =
660 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
661 auto criticalInterface =
662 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
663
664 if ((warningInterface != sensorMap.end()) ||
665 (criticalInterface != sensorMap.end()))
666 {
667 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
668
669 if (sensorPair == sensorMap.end())
670 {
671 // should not have been able to find a sensor not implementing
672 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700673 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700674 }
675
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800676 double max = 0;
677 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700678 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700679
680 int16_t mValue = 0;
681 int16_t bValue = 0;
682 int8_t rExp = 0;
683 int8_t bExp = 0;
684 bool bSigned = false;
685
686 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
687 {
James Feist902c4c52019-04-16 14:51:31 -0700688 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700689 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700690 if (warningInterface != sensorMap.end())
691 {
692 auto &warningMap = warningInterface->second;
693
694 auto warningHigh = warningMap.find("WarningHigh");
695 auto warningLow = warningMap.find("WarningLow");
696
697 if (warningHigh != warningMap.end())
698 {
James Feist902c4c52019-04-16 14:51:31 -0700699
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700700 double value =
701 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700702 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700703 value, mValue, rExp, bValue, bExp, bSigned);
704 }
705 if (warningLow != warningMap.end())
706 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700707 double value =
708 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700709 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700710 value, mValue, rExp, bValue, bExp, bSigned);
711 }
712 }
713 if (criticalInterface != sensorMap.end())
714 {
715 auto &criticalMap = criticalInterface->second;
716
717 auto criticalHigh = criticalMap.find("CriticalHigh");
718 auto criticalLow = criticalMap.find("CriticalLow");
719
720 if (criticalHigh != criticalMap.end())
721 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700722 double value =
723 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700724 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700725 value, mValue, rExp, bValue, bExp, bSigned);
726 }
727 if (criticalLow != criticalMap.end())
728 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700729 double value =
730 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700731 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700732 value, mValue, rExp, bValue, bExp, bSigned);
733 }
734 }
735 }
James Feist902c4c52019-04-16 14:51:31 -0700736 return resp;
737}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700738
James Feist902c4c52019-04-16 14:51:31 -0700739ipmi::RspType<uint8_t, // readable
740 uint8_t, // lowerNCrit
741 uint8_t, // lowerCrit
742 uint8_t, // lowerNrecoverable
743 uint8_t, // upperNC
744 uint8_t, // upperCrit
745 uint8_t> // upperNRecoverable
746 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
747{
748 std::string connection;
749 std::string path;
750
751 auto status = getSensorConnection(sensorNumber, connection, path);
752 if (status)
753 {
754 return ipmi::response(status);
755 }
756
757 SensorMap sensorMap;
758 if (!getSensorMap(connection, path, sensorMap))
759 {
760 return ipmi::responseResponseError();
761 }
762
763 IPMIThresholds thresholdData;
764 try
765 {
766 thresholdData = getIPMIThresholds(sensorMap);
767 }
768 catch (std::exception &)
769 {
770 return ipmi::responseResponseError();
771 }
772
773 uint8_t readable = 0;
774 uint8_t lowerNC = 0;
775 uint8_t lowerCritical = 0;
776 uint8_t lowerNonRecoverable = 0;
777 uint8_t upperNC = 0;
778 uint8_t upperCritical = 0;
779 uint8_t upperNonRecoverable = 0;
780
781 if (thresholdData.warningHigh)
782 {
783 readable |=
784 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
785 upperNC = *thresholdData.warningHigh;
786 }
787 if (thresholdData.warningLow)
788 {
789 readable |=
790 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
791 lowerNC = *thresholdData.warningLow;
792 }
793
794 if (thresholdData.criticalHigh)
795 {
796 readable |=
797 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
798 upperCritical = *thresholdData.criticalHigh;
799 }
800 if (thresholdData.criticalLow)
801 {
802 readable |=
803 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
804 lowerCritical = *thresholdData.criticalLow;
805 }
806
807 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
808 lowerNonRecoverable, upperNC, upperCritical,
809 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700810}
811
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000812/** @brief implements the get Sensor event enable command
813 * @param sensorNumber - sensor number
814 *
815 * @returns IPMI completion code plus response data
816 * - enabled - Sensor Event messages
817 * - assertionEnabledLsb - Assertion event messages
818 * - assertionEnabledMsb - Assertion event messages
819 * - deassertionEnabledLsb - Deassertion event messages
820 * - deassertionEnabledMsb - Deassertion event messages
821 */
822
823ipmi::RspType<uint8_t, // enabled
824 uint8_t, // assertionEnabledLsb
825 uint8_t, // assertionEnabledMsb
826 uint8_t, // deassertionEnabledLsb
827 uint8_t> // deassertionEnabledMsb
828 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700829{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700830 std::string connection;
831 std::string path;
832
Patrick Venturea41714c2019-09-25 16:59:41 -0700833 uint8_t enabled = 0;
834 uint8_t assertionEnabledLsb = 0;
835 uint8_t assertionEnabledMsb = 0;
836 uint8_t deassertionEnabledLsb = 0;
837 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000838
839 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700840 if (status)
841 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000842 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700843 }
844
845 SensorMap sensorMap;
846 if (!getSensorMap(connection, path, sensorMap))
847 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000848 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700849 }
850
851 auto warningInterface =
852 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
853 auto criticalInterface =
854 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700855 if ((warningInterface != sensorMap.end()) ||
856 (criticalInterface != sensorMap.end()))
857 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000858 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700859 IPMISensorEventEnableByte2::sensorScanningEnable);
860 if (warningInterface != sensorMap.end())
861 {
862 auto &warningMap = warningInterface->second;
863
864 auto warningHigh = warningMap.find("WarningHigh");
865 auto warningLow = warningMap.find("WarningLow");
866 if (warningHigh != warningMap.end())
867 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000868 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700869 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000870 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700871 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
872 }
873 if (warningLow != warningMap.end())
874 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000875 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700876 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000877 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700878 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
879 }
880 }
881 if (criticalInterface != sensorMap.end())
882 {
883 auto &criticalMap = criticalInterface->second;
884
885 auto criticalHigh = criticalMap.find("CriticalHigh");
886 auto criticalLow = criticalMap.find("CriticalLow");
887
888 if (criticalHigh != criticalMap.end())
889 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000890 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700891 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000892 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700893 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
894 }
895 if (criticalLow != criticalMap.end())
896 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000897 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700898 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000899 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700900 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
901 }
902 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700903 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000904
905 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
906 assertionEnabledMsb, deassertionEnabledLsb,
907 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700908}
909
910ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
911 ipmi_request_t request,
912 ipmi_response_t response,
913 ipmi_data_len_t dataLen,
914 ipmi_context_t context)
915{
916 if (*dataLen != 1)
917 {
918 *dataLen = 0;
919 return IPMI_CC_REQ_DATA_LEN_INVALID;
920 }
921 *dataLen = 0; // default to 0 in case of an error
922
923 uint8_t sensnum = *(static_cast<uint8_t *>(request));
924
925 std::string connection;
926 std::string path;
927
928 auto status = getSensorConnection(sensnum, connection, path);
929 if (status)
930 {
931 return status;
932 }
933
934 SensorMap sensorMap;
935 if (!getSensorMap(connection, path, sensorMap))
936 {
937 return IPMI_CC_RESPONSE_ERROR;
938 }
939
940 auto warningInterface =
941 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
942 auto criticalInterface =
943 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
944
945 // zero out response buff
946 auto responseClear = static_cast<uint8_t *>(response);
947 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
948 auto resp = static_cast<SensorEventStatusResp *>(response);
949 resp->enabled =
950 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
951
James Feist392786a2019-03-19 13:36:10 -0700952 std::optional<bool> criticalDeassertHigh =
953 thresholdDeassertMap[path]["CriticalAlarmHigh"];
954 std::optional<bool> criticalDeassertLow =
955 thresholdDeassertMap[path]["CriticalAlarmLow"];
956 std::optional<bool> warningDeassertHigh =
957 thresholdDeassertMap[path]["WarningAlarmHigh"];
958 std::optional<bool> warningDeassertLow =
959 thresholdDeassertMap[path]["WarningAlarmLow"];
960
961 if (criticalDeassertHigh && !*criticalDeassertHigh)
962 {
963 resp->deassertionsMSB |= static_cast<uint8_t>(
964 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
965 }
966 if (criticalDeassertLow && !*criticalDeassertLow)
967 {
968 resp->deassertionsMSB |= static_cast<uint8_t>(
969 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
970 }
971 if (warningDeassertHigh && !*warningDeassertHigh)
972 {
973 resp->deassertionsLSB |= static_cast<uint8_t>(
974 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
975 }
976 if (warningDeassertLow && !*warningDeassertLow)
977 {
978 resp->deassertionsLSB |= static_cast<uint8_t>(
979 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
980 }
981
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700982 if ((warningInterface != sensorMap.end()) ||
983 (criticalInterface != sensorMap.end()))
984 {
985 resp->enabled = static_cast<uint8_t>(
986 IPMISensorEventEnableByte2::eventMessagesEnable);
987 if (warningInterface != sensorMap.end())
988 {
989 auto &warningMap = warningInterface->second;
990
991 auto warningHigh = warningMap.find("WarningAlarmHigh");
992 auto warningLow = warningMap.find("WarningAlarmLow");
993 auto warningHighAlarm = false;
994 auto warningLowAlarm = false;
995
996 if (warningHigh != warningMap.end())
997 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700998 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700999 }
1000 if (warningLow != warningMap.end())
1001 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001002 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001003 }
1004 if (warningHighAlarm)
1005 {
1006 resp->assertionsLSB |= static_cast<uint8_t>(
1007 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1008 }
1009 if (warningLowAlarm)
1010 {
1011 resp->assertionsLSB |= 1; // lower nc going low
1012 }
1013 }
1014 if (criticalInterface != sensorMap.end())
1015 {
1016 auto &criticalMap = criticalInterface->second;
1017
1018 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1019 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1020 auto criticalHighAlarm = false;
1021 auto criticalLowAlarm = false;
1022
1023 if (criticalHigh != criticalMap.end())
1024 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001025 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001026 }
1027 if (criticalLow != criticalMap.end())
1028 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001029 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001030 }
1031 if (criticalHighAlarm)
1032 {
1033 resp->assertionsMSB |= static_cast<uint8_t>(
1034 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1035 }
1036 if (criticalLowAlarm)
1037 {
1038 resp->assertionsLSB |= static_cast<uint8_t>(
1039 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1040 }
1041 }
1042 *dataLen = sizeof(SensorEventStatusResp);
1043 }
1044
1045 // no thresholds enabled, don't need assertionMSB
1046 else
1047 {
1048 *dataLen = sizeof(SensorEventStatusResp) - 1;
1049 }
1050
1051 return IPMI_CC_OK;
1052}
1053
1054/* end sensor commands */
1055
1056/* storage commands */
1057
James Feist74c50c62019-08-14 14:18:41 -07001058ipmi::RspType<uint8_t, // sdr version
1059 uint16_t, // record count
1060 uint16_t, // free space
1061 uint32_t, // most recent addition
1062 uint32_t, // most recent erase
1063 uint8_t // operationSupport
1064 >
1065 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001066{
James Feist74c50c62019-08-14 14:18:41 -07001067 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001068 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1069 {
James Feist74c50c62019-08-14 14:18:41 -07001070 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001071 }
1072
James Feist74c50c62019-08-14 14:18:41 -07001073 size_t fruCount = 0;
1074 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1075 if (ret != ipmi::ccSuccess)
1076 {
1077 return ipmi::response(ret);
1078 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001079
James Feist74c50c62019-08-14 14:18:41 -07001080 uint16_t recordCount =
1081 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001082
James Feist74c50c62019-08-14 14:18:41 -07001083 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001084 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001085
1086 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001087 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001088 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001090 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1091 unspecifiedFreeSpace, sdrLastAdd,
1092 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001093}
1094
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001095/** @brief implements the get SDR allocation info command
1096 *
1097 * @returns IPMI completion code plus response data
1098 * - allocUnits - Number of possible allocation units
1099 * - allocUnitSize - Allocation unit size in bytes.
1100 * - allocUnitFree - Number of free allocation units
1101 * - allocUnitLargestFree - Largest free block in allocation units
1102 * - maxRecordSize - Maximum record size in allocation units.
1103 */
1104ipmi::RspType<uint16_t, // allocUnits
1105 uint16_t, // allocUnitSize
1106 uint16_t, // allocUnitFree
1107 uint16_t, // allocUnitLargestFree
1108 uint8_t // maxRecordSize
1109 >
1110 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001111{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001112 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001113 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001114
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001115 constexpr uint16_t allocUnitFree = 0;
1116 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001117 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001118 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001119
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001120 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1121 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001122}
1123
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001124/** @brief implements the reserve SDR command
1125 * @returns IPMI completion code plus response data
1126 * - sdrReservationID
1127 */
1128ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001129{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001130 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001131 if (sdrReservationID == 0)
1132 {
1133 sdrReservationID++;
1134 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001135
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001136 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001137}
1138
James Feistb49a98a2019-04-16 13:48:09 -07001139ipmi::RspType<uint16_t, // next record ID
1140 std::vector<uint8_t> // payload
1141 >
1142 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1143 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001144{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001145 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001146
1147 // reservation required for partial reads with non zero offset into
1148 // record
James Feistb49a98a2019-04-16 13:48:09 -07001149 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001150 {
James Feistb49a98a2019-04-16 13:48:09 -07001151 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001152 }
1153
1154 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1155 {
James Feistb49a98a2019-04-16 13:48:09 -07001156 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001157 }
1158
1159 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001160 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1161 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001162 {
James Feistb49a98a2019-04-16 13:48:09 -07001163 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001164 }
1165
James Feist74c50c62019-08-14 14:18:41 -07001166 size_t lastRecord =
1167 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001168 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001169 {
James Feistb49a98a2019-04-16 13:48:09 -07001170 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001171 }
James Feistb49a98a2019-04-16 13:48:09 -07001172 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173 {
James Feistb49a98a2019-04-16 13:48:09 -07001174 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001175 }
1176
James Feistb49a98a2019-04-16 13:48:09 -07001177 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001178
James Feistb49a98a2019-04-16 13:48:09 -07001179 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001180 {
James Feist74c50c62019-08-14 14:18:41 -07001181 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001182 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001183 if (fruIndex >= fruCount)
1184 {
James Feist74c50c62019-08-14 14:18:41 -07001185 // handle type 12 hardcoded records
1186 size_t type12Index = fruIndex - fruCount;
1187 if (type12Index >= ipmi::storage::type12Count ||
1188 offset > sizeof(Type12Record))
1189 {
1190 return ipmi::responseInvalidFieldRequest();
1191 }
1192 std::vector<uint8_t> record =
1193 ipmi::storage::getType12SDRs(type12Index, recordID);
1194 if (record.size() < (offset + bytesToRead))
1195 {
1196 bytesToRead = record.size() - offset;
1197 }
James Feistb49a98a2019-04-16 13:48:09 -07001198
James Feist74c50c62019-08-14 14:18:41 -07001199 recordData.insert(recordData.end(), record.begin() + offset,
1200 record.begin() + offset + bytesToRead);
1201 }
1202 else
1203 {
1204 // handle fru records
1205 get_sdr::SensorDataFruRecord data;
1206 if (offset > sizeof(data))
1207 {
1208 return ipmi::responseInvalidFieldRequest();
1209 }
1210 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1211 if (ret != IPMI_CC_OK)
1212 {
1213 return ipmi::response(ret);
1214 }
1215 data.header.record_id_msb = recordID << 8;
1216 data.header.record_id_lsb = recordID & 0xFF;
1217 if (sizeof(data) < (offset + bytesToRead))
1218 {
1219 bytesToRead = sizeof(data) - offset;
1220 }
1221
1222 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1223 recordData.insert(recordData.end(), respStart,
1224 respStart + bytesToRead);
1225 }
James Feistb49a98a2019-04-16 13:48:09 -07001226
1227 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001228 }
1229
1230 std::string connection;
1231 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001232 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001233 for (const auto &sensor : sensorTree)
1234 {
1235 if (sensorIndex-- == 0)
1236 {
1237 if (!sensor.second.size())
1238 {
James Feistb49a98a2019-04-16 13:48:09 -07001239 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001240 }
1241 connection = sensor.second.begin()->first;
1242 path = sensor.first;
1243 break;
1244 }
1245 }
1246
1247 SensorMap sensorMap;
1248 if (!getSensorMap(connection, path, sensorMap))
1249 {
James Feistb49a98a2019-04-16 13:48:09 -07001250 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001251 }
James Feistb49a98a2019-04-16 13:48:09 -07001252 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001253 get_sdr::SensorDataFullRecord record = {0};
1254
James Feistb49a98a2019-04-16 13:48:09 -07001255 record.header.record_id_msb = recordID << 8;
1256 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001257 record.header.sdr_version = ipmiSdrVersion;
1258 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1259 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1260 sizeof(get_sdr::SensorDataRecordHeader);
1261 record.key.owner_id = 0x20;
1262 record.key.owner_lun = 0x0;
1263 record.key.sensor_number = sensornumber;
1264
1265 record.body.entity_id = 0x0;
1266 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001267 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001268 record.body.sensor_type = getSensorTypeFromPath(path);
1269 std::string type = getSensorTypeStringFromPath(path);
1270 auto typeCstr = type.c_str();
1271 auto findUnits = sensorUnits.find(typeCstr);
1272 if (findUnits != sensorUnits.end())
1273 {
1274 record.body.sensor_units_2_base =
1275 static_cast<uint8_t>(findUnits->second);
1276 } // else default 0x0 unspecified
1277
1278 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1279
1280 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1281 if (sensorObject == sensorMap.end())
1282 {
James Feistb49a98a2019-04-16 13:48:09 -07001283 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001284 }
1285
1286 auto maxObject = sensorObject->second.find("MaxValue");
1287 auto minObject = sensorObject->second.find("MinValue");
1288 double max = 128;
1289 double min = -127;
1290 if (maxObject != sensorObject->second.end())
1291 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001292 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001293 }
1294
1295 if (minObject != sensorObject->second.end())
1296 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001297 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001298 }
1299
Yong Li1f2eb5e2019-05-23 14:07:17 +08001300 int16_t mValue = 0;
1301 int8_t rExp = 0;
1302 int16_t bValue = 0;
1303 int8_t bExp = 0;
1304 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001305
1306 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1307 {
James Feistb49a98a2019-04-16 13:48:09 -07001308 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001309 }
1310
1311 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1312 record.body.m_lsb = mValue & 0xFF;
1313
1314 // move the smallest bit of the MSB into place (bit 9)
1315 // the MSbs are bits 7:8 in m_msb_and_tolerance
1316 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1317
1318 // assign the negative
1319 if (mValue < 0)
1320 {
1321 mMsb |= (1 << 7);
1322 }
1323 record.body.m_msb_and_tolerance = mMsb;
1324
1325 record.body.b_lsb = bValue & 0xFF;
1326
1327 // move the smallest bit of the MSB into place
1328 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1329 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1330
1331 // assign the negative
1332 if (bValue < 0)
1333 {
1334 bMsb |= (1 << 7);
1335 }
1336 record.body.b_msb_and_accuracy_lsb = bMsb;
1337
1338 record.body.r_b_exponents = bExp & 0x7;
1339 if (bExp < 0)
1340 {
1341 record.body.r_b_exponents |= 1 << 3;
1342 }
1343 record.body.r_b_exponents = (rExp & 0x7) << 4;
1344 if (rExp < 0)
1345 {
1346 record.body.r_b_exponents |= 1 << 7;
1347 }
1348
1349 // todo fill out rest of units
1350 if (bSigned)
1351 {
1352 record.body.sensor_units_1 = 1 << 7;
1353 }
1354
1355 // populate sensor name from path
1356 std::string name;
1357 size_t nameStart = path.rfind("/");
1358 if (nameStart != std::string::npos)
1359 {
1360 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1361 }
1362
1363 std::replace(name.begin(), name.end(), '_', ' ');
1364 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1365 {
James Feist979a2322019-05-15 09:06:54 -07001366 // try to not truncate by replacing common words
1367 constexpr std::array<std::pair<const char *, const char *>, 2>
1368 replaceWords = {std::make_pair("Output", "Out"),
1369 std::make_pair("Input", "In")};
1370 for (const auto &[find, replace] : replaceWords)
1371 {
1372 boost::replace_all(name, find, replace);
1373 }
1374
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001375 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1376 }
1377 record.body.id_string_info = name.size();
1378 std::strncpy(record.body.id_string, name.c_str(),
1379 sizeof(record.body.id_string));
1380
James Feistc4b15bc2019-04-16 15:41:39 -07001381 IPMIThresholds thresholdData;
1382 try
1383 {
1384 thresholdData = getIPMIThresholds(sensorMap);
1385 }
1386 catch (std::exception &)
1387 {
1388 return ipmi::responseResponseError();
1389 }
1390
1391 if (thresholdData.criticalHigh)
1392 {
1393 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1394 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1395 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1396 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1397 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1398 record.body.discrete_reading_setting_mask[0] |=
1399 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1400 }
1401 if (thresholdData.warningHigh)
1402 {
1403 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1404 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1405 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1406 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1407 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1408 record.body.discrete_reading_setting_mask[0] |=
1409 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1410 }
1411 if (thresholdData.criticalLow)
1412 {
1413 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1414 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1415 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1416 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1417 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1418 record.body.discrete_reading_setting_mask[0] |=
1419 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1420 }
1421 if (thresholdData.warningLow)
1422 {
1423 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1424 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1425 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1426 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1427 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1428 record.body.discrete_reading_setting_mask[0] |=
1429 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1430 }
1431
1432 // everything that is readable is setable
1433 record.body.discrete_reading_setting_mask[1] =
1434 record.body.discrete_reading_setting_mask[0];
1435
James Feistb49a98a2019-04-16 13:48:09 -07001436 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001437 {
James Feistb49a98a2019-04-16 13:48:09 -07001438 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001439 }
1440
James Feistb49a98a2019-04-16 13:48:09 -07001441 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1442 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001443
James Feistb49a98a2019-04-16 13:48:09 -07001444 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001445}
1446/* end storage commands */
1447
1448void registerSensorFunctions()
1449{
1450 // get firmware version information
1451 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1452 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1453
1454 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001455 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1456 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001457
1458 // <Set Sensor Reading and Event Status>
1459 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001460 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001461 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1462
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001463 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001464 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1465 ipmi::sensor_event::cmdPlatformEvent,
1466 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001467
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001468 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001469 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1470 ipmi::sensor_event::cmdGetSensorReading,
1471 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001472
1473 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001474 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1475 ipmi::sensor_event::cmdGetSensorThreshold,
1476 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001477
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001478 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001479 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1480 ipmi::sensor_event::cmdSetSensorThreshold,
1481 ipmi::Privilege::Operator,
1482 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001483
1484 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001485 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1486 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001487 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001488
1489 // <Get Sensor Event Status>
1490 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001491 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1492 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001493
1494 // register all storage commands for both Sensor and Storage command
1495 // versions
1496
1497 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001498 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1499 ipmi::storage::cmdGetSdrRepositoryInfo,
1500 ipmi::Privilege::User,
1501 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001502
1503 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001504 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1505 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1506 ipmi::Privilege::User,
1507 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001508
1509 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001510 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1511 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001512 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001513
Vernon Mauery98bbf692019-09-16 11:14:59 -07001514 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1515 ipmi::storage::cmdReserveSdrRepository,
1516 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001517
1518 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001519 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1520 ipmi::sensor_event::cmdGetDeviceSdr,
1521 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001522
Vernon Mauery98bbf692019-09-16 11:14:59 -07001523 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1524 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1525 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001526}
1527} // namespace ipmi