blob: 7fc11a0ba790099e6496a49be8711884ed2d6ab4 [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>
Patrick Venture38f46f22019-09-25 17:41:26 -070035#include <utility>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070036
37namespace ipmi
38{
39using ManagedObjectType =
40 std::map<sdbusplus::message::object_path,
41 std::map<std::string, std::map<std::string, DbusVariant>>>;
42
43using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
44
45static constexpr int sensorListUpdatePeriod = 10;
46static constexpr int sensorMapUpdatePeriod = 2;
47
48constexpr size_t maxSDRTotalSize =
49 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
50constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
51
52static uint16_t sdrReservationID;
53static uint32_t sdrLastAdd = noTimestamp;
54static uint32_t sdrLastRemove = noTimestamp;
55
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053056SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070057static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
58
Jason M. Bills17add592018-11-12 14:30:12 -080059// Specify the comparison required to sort and find char* map objects
60struct CmpStr
61{
62 bool operator()(const char *a, const char *b) const
63 {
64 return std::strcmp(a, b) < 0;
65 }
66};
67const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
68 sensorUnits{{{"temperature", SensorUnits::degreesC},
69 {"voltage", SensorUnits::volts},
70 {"current", SensorUnits::amps},
71 {"fan_tach", SensorUnits::rpm},
72 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070073
74void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070075
76static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070077 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070078 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
79 "sensors/'",
80 [](sdbusplus::message::message &m) {
81 sensorTree.clear();
82 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
83 std::chrono::system_clock::now().time_since_epoch())
84 .count();
85 });
86
87static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070088 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070089 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
90 "sensors/'",
91 [](sdbusplus::message::message &m) {
92 sensorTree.clear();
93 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
94 std::chrono::system_clock::now().time_since_epoch())
95 .count();
96 });
97
James Feist392786a2019-03-19 13:36:10 -070098// this keeps track of deassertions for sensor event status command. A
99// deasertion can only happen if an assertion was seen first.
100static boost::container::flat_map<
101 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
102 thresholdDeassertMap;
103
104static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700105 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700106 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
107 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
108 [](sdbusplus::message::message &m) {
109 boost::container::flat_map<std::string, std::variant<bool, double>>
110 values;
111 m.read(std::string(), values);
112
113 auto findAssert =
114 std::find_if(values.begin(), values.end(), [](const auto &pair) {
115 return pair.first.find("Alarm") != std::string::npos;
116 });
117 if (findAssert != values.end())
118 {
119 auto ptr = std::get_if<bool>(&(findAssert->second));
120 if (ptr == nullptr)
121 {
122 phosphor::logging::log<phosphor::logging::level::ERR>(
123 "thresholdChanged: Assert non bool");
124 return;
125 }
126 if (*ptr)
127 {
128 phosphor::logging::log<phosphor::logging::level::INFO>(
129 "thresholdChanged: Assert",
130 phosphor::logging::entry("SENSOR=%s", m.get_path()));
131 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
132 }
133 else
134 {
135 auto &value =
136 thresholdDeassertMap[m.get_path()][findAssert->first];
137 if (value)
138 {
139 phosphor::logging::log<phosphor::logging::level::INFO>(
140 "thresholdChanged: deassert",
141 phosphor::logging::entry("SENSOR=%s", m.get_path()));
142 value = *ptr;
143 }
144 }
145 }
146 });
147
James Feistaecaef72019-04-26 10:30:32 -0700148static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
149 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700150{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700151 max = 127;
152 min = -128;
153
James Feistaecaef72019-04-26 10:30:32 -0700154 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
155 auto critical =
156 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
157 auto warning =
158 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
159
160 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700161 {
James Feistaecaef72019-04-26 10:30:32 -0700162 auto maxMap = sensorObject->second.find("MaxValue");
163 auto minMap = sensorObject->second.find("MinValue");
164
165 if (maxMap != sensorObject->second.end())
166 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700167 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700168 }
169 if (minMap != sensorObject->second.end())
170 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700171 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700172 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700173 }
James Feistaecaef72019-04-26 10:30:32 -0700174 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700175 {
James Feistaecaef72019-04-26 10:30:32 -0700176 auto lower = critical->second.find("CriticalLow");
177 auto upper = critical->second.find("CriticalHigh");
178 if (lower != critical->second.end())
179 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700180 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700181 min = std::min(value, min);
182 }
183 if (upper != critical->second.end())
184 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700185 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700186 max = std::max(value, max);
187 }
188 }
189 if (warning != sensorMap.end())
190 {
191
192 auto lower = warning->second.find("WarningLow");
193 auto upper = warning->second.find("WarningHigh");
194 if (lower != warning->second.end())
195 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700196 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700197 min = std::min(value, min);
198 }
199 if (upper != warning->second.end())
200 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700201 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700202 max = std::max(value, max);
203 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700204 }
205}
206
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700207static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
208 SensorMap &sensorMap)
209{
210 static boost::container::flat_map<
211 std::string, std::chrono::time_point<std::chrono::steady_clock>>
212 updateTimeMap;
213
214 auto updateFind = updateTimeMap.find(sensorConnection);
215 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
216 if (updateFind != updateTimeMap.end())
217 {
218 lastUpdate = updateFind->second;
219 }
220
221 auto now = std::chrono::steady_clock::now();
222
223 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
224 .count() > sensorMapUpdatePeriod)
225 {
226 updateTimeMap[sensorConnection] = now;
227
Vernon Mauery15419dd2019-05-24 09:40:30 -0700228 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
229 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700230 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
231 "GetManagedObjects");
232
233 ManagedObjectType managedObjects;
234 try
235 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700236 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700237 reply.read(managedObjects);
238 }
239 catch (sdbusplus::exception_t &)
240 {
241 phosphor::logging::log<phosphor::logging::level::ERR>(
242 "Error getting managed objects from connection",
243 phosphor::logging::entry("CONNECTION=%s",
244 sensorConnection.c_str()));
245 return false;
246 }
247
248 SensorCache[sensorConnection] = managedObjects;
249 }
250 auto connection = SensorCache.find(sensorConnection);
251 if (connection == SensorCache.end())
252 {
253 return false;
254 }
255 auto path = connection->second.find(sensorPath);
256 if (path == connection->second.end())
257 {
258 return false;
259 }
260 sensorMap = path->second;
261
262 return true;
263}
264
265/* sensor commands */
266ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
267 ipmi_request_t request,
268 ipmi_response_t response,
269 ipmi_data_len_t dataLen,
270 ipmi_context_t context)
271{
272 *dataLen = 0;
273 printCommand(+netfn, +cmd);
274 return IPMI_CC_INVALID;
275}
276
James Feist7aaf3fe2019-06-25 11:52:11 -0700277namespace meHealth
278{
279constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
280constexpr const char *path = "/xyz/openbmc_project/status/me";
281constexpr const char *interface = "xyz.openbmc_project.SetHealth";
282constexpr const char *method = "SetHealth";
283constexpr const char *critical = "critical";
284constexpr const char *warning = "warning";
285constexpr const char *ok = "ok";
286} // namespace meHealth
287
288static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
289{
290 constexpr const std::array<uint8_t, 10> critical = {
291 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
292 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
293 0x1A};
294
295 std::string state;
296 if (std::find(critical.begin(), critical.end(), eventData2) !=
297 critical.end())
298 {
299 state = meHealth::critical;
300 }
301 // special case 0x3 as we only care about a few states
302 else if (eventData2 == 0x3)
303 {
304 if (eventData3 <= 0x2)
305 {
306 state = meHealth::warning;
307 }
308 else
309 {
310 return;
311 }
312 }
313 else if (std::find(warning.begin(), warning.end(), eventData2) !=
314 warning.end())
315 {
316 state = meHealth::warning;
317 }
318 else
319 {
320 return;
321 }
322 if (disable)
323 {
324 state = meHealth::ok;
325 }
326
327 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
328 auto setHealth =
329 dbus->new_method_call(meHealth::busname, meHealth::path,
330 meHealth::interface, meHealth::method);
331 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
332 try
333 {
334 dbus->call(setHealth);
335 }
336 catch (sdbusplus::exception_t &)
337 {
338 phosphor::logging::log<phosphor::logging::level::ERR>(
339 "Failed to set ME Health");
340 }
341}
342
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700343ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
344{
James Feist7aaf3fe2019-06-25 11:52:11 -0700345 constexpr const uint8_t meId = 0x2C;
346 constexpr const uint8_t meSensorNum = 0x17;
347 constexpr const uint8_t disabled = 0x80;
348
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700349 uint8_t generatorID = 0;
350 uint8_t evmRev = 0;
351 uint8_t sensorType = 0;
352 uint8_t sensorNum = 0;
353 uint8_t eventType = 0;
354 uint8_t eventData1 = 0;
355 std::optional<uint8_t> eventData2 = 0;
356 std::optional<uint8_t> eventData3 = 0;
357
358 // todo: This check is supposed to be based on the incoming channel.
359 // e.g. system channel will provide upto 8 bytes including generator
360 // ID, but ipmb channel will provide only up to 7 bytes without the
361 // generator ID.
362 // Support for this check is coming in future patches, so for now just base
363 // it on if the first byte is the EvMRev (0x04).
364 if (p.size() && p.data()[0] == 0x04)
365 {
366 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
367 eventData2, eventData3);
368 // todo: the generator ID for this channel is supposed to come from the
369 // IPMB requesters slave address. Support for this is coming in future
370 // patches, so for now just assume it is coming from the ME (0x2C).
371 generatorID = 0x2C;
372 }
373 else
374 {
375 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
376 eventData1, eventData2, eventData3);
377 }
378 if (!p.fullyUnpacked())
379 {
380 return ipmi::responseReqDataLenInvalid();
381 }
382
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700383 // Send this request to the Redfish hooks to log it as a Redfish message
384 // instead. There is no need to add it to the SEL, so just return success.
385 intel_oem::ipmi::sel::checkRedfishHooks(
386 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
387 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700388
James Feist7aaf3fe2019-06-25 11:52:11 -0700389 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
390 eventData3)
391 {
392 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
393 }
394
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700395 return ipmi::responseSuccess();
396}
397
James Feist0cd014a2019-04-08 15:04:33 -0700398ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
399 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700400{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700401 std::string connection;
402 std::string path;
403
404 auto status = getSensorConnection(sensnum, connection, path);
405 if (status)
406 {
James Feist0cd014a2019-04-08 15:04:33 -0700407 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700408 }
409
410 SensorMap sensorMap;
411 if (!getSensorMap(connection, path, sensorMap))
412 {
James Feist0cd014a2019-04-08 15:04:33 -0700413 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700414 }
415 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
416
417 if (sensorObject == sensorMap.end() ||
418 sensorObject->second.find("Value") == sensorObject->second.end())
419 {
James Feist0cd014a2019-04-08 15:04:33 -0700420 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700421 }
James Feist0cd014a2019-04-08 15:04:33 -0700422 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700423 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700424
Yong Li1f2eb5e2019-05-23 14:07:17 +0800425 double max = 0;
426 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700427 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700428
429 int16_t mValue = 0;
430 int16_t bValue = 0;
431 int8_t rExp = 0;
432 int8_t bExp = 0;
433 bool bSigned = false;
434
435 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
436 {
James Feist0cd014a2019-04-08 15:04:33 -0700437 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700438 }
439
James Feist0cd014a2019-04-08 15:04:33 -0700440 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700441 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700442 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700443 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700444 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800445 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700446
James Feist0cd014a2019-04-08 15:04:33 -0700447 uint8_t thresholds = 0;
448
449 auto warningObject =
450 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
451 if (warningObject != sensorMap.end())
452 {
453 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
454 auto alarmLow = warningObject->second.find("WarningAlarmLow");
455 if (alarmHigh != warningObject->second.end())
456 {
457 if (std::get<bool>(alarmHigh->second))
458 {
459 thresholds |= static_cast<uint8_t>(
460 IPMISensorReadingByte3::upperNonCritical);
461 }
462 }
463 if (alarmLow != warningObject->second.end())
464 {
465 if (std::get<bool>(alarmLow->second))
466 {
467 thresholds |= static_cast<uint8_t>(
468 IPMISensorReadingByte3::lowerNonCritical);
469 }
470 }
471 }
472
473 auto criticalObject =
474 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
475 if (criticalObject != sensorMap.end())
476 {
477 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
478 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
479 if (alarmHigh != criticalObject->second.end())
480 {
481 if (std::get<bool>(alarmHigh->second))
482 {
483 thresholds |=
484 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
485 }
486 }
487 if (alarmLow != criticalObject->second.end())
488 {
489 if (std::get<bool>(alarmLow->second))
490 {
491 thresholds |=
492 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
493 }
494 }
495 }
496
497 // no discrete as of today so optional byte is never returned
498 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700499}
500
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000501/** @brief implements the Set Sensor threshold command
502 * @param sensorNumber - sensor number
503 * @param lowerNonCriticalThreshMask
504 * @param lowerCriticalThreshMask
505 * @param lowerNonRecovThreshMask
506 * @param upperNonCriticalThreshMask
507 * @param upperCriticalThreshMask
508 * @param upperNonRecovThreshMask
509 * @param reserved
510 * @param lowerNonCritical - lower non-critical threshold
511 * @param lowerCritical - Lower critical threshold
512 * @param lowerNonRecoverable - Lower non recovarable threshold
513 * @param upperNonCritical - Upper non-critical threshold
514 * @param upperCritical - Upper critical
515 * @param upperNonRecoverable - Upper Non-recoverable
516 *
517 * @returns IPMI completion code
518 */
519ipmi::RspType<> ipmiSenSetSensorThresholds(
520 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
521 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
522 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
523 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
524 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
525 uint8_t upperNonCritical, uint8_t upperCritical,
526 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700527{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000528 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700529
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000530 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700531 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000532 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700533 }
534
535 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000536 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700537 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000538 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700539 }
540
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000541 // if none of the threshold mask are set, nothing to do
542 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
543 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
544 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700545 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000546 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700547 }
548
549 std::string connection;
550 std::string path;
551
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000552 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700553 if (status)
554 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000555 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700556 }
557 SensorMap sensorMap;
558 if (!getSensorMap(connection, path, sensorMap))
559 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000560 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700561 }
562
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700563 double max = 0;
564 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700565 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700566
567 int16_t mValue = 0;
568 int16_t bValue = 0;
569 int8_t rExp = 0;
570 int8_t bExp = 0;
571 bool bSigned = false;
572
573 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
574 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000575 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700576 }
577
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700578 // store a vector of property name, value to set, and interface
579 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
580
581 // define the indexes of the tuple
582 constexpr uint8_t propertyName = 0;
583 constexpr uint8_t thresholdValue = 1;
584 constexpr uint8_t interface = 2;
585 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000586 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700587 {
588 auto findThreshold =
589 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
590 if (findThreshold == sensorMap.end())
591 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000592 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700593 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000594 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700595 {
596 auto findLower = findThreshold->second.find("CriticalLow");
597 if (findLower == findThreshold->second.end())
598 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000599 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700600 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000601 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700602 findThreshold->first);
603 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000604 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700605 {
606 auto findUpper = findThreshold->second.find("CriticalHigh");
607 if (findUpper == findThreshold->second.end())
608 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000609 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700610 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000611 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700612 findThreshold->first);
613 }
614 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000615 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700616 {
617 auto findThreshold =
618 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
619 if (findThreshold == sensorMap.end())
620 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000621 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700622 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000623 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700624 {
625 auto findLower = findThreshold->second.find("WarningLow");
626 if (findLower == findThreshold->second.end())
627 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000628 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700629 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 findThreshold->first);
632 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000633 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700634 {
635 auto findUpper = findThreshold->second.find("WarningHigh");
636 if (findUpper == findThreshold->second.end())
637 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000638 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700639 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000640 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700641 findThreshold->first);
642 }
643 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644 for (const auto &property : thresholdsToSet)
645 {
646 // from section 36.3 in the IPMI Spec, assume all linear
647 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
648 (bValue * std::pow(10, bExp))) *
649 std::pow(10, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700650 setDbusProperty(
651 *getSdBus(), connection, path, std::get<interface>(property),
652 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700653 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000654 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700655}
656
James Feist902c4c52019-04-16 14:51:31 -0700657IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700658{
James Feist902c4c52019-04-16 14:51:31 -0700659 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700660 auto warningInterface =
661 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
662 auto criticalInterface =
663 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
664
665 if ((warningInterface != sensorMap.end()) ||
666 (criticalInterface != sensorMap.end()))
667 {
668 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
669
670 if (sensorPair == sensorMap.end())
671 {
672 // should not have been able to find a sensor not implementing
673 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700674 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700675 }
676
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800677 double max = 0;
678 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700679 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700680
681 int16_t mValue = 0;
682 int16_t bValue = 0;
683 int8_t rExp = 0;
684 int8_t bExp = 0;
685 bool bSigned = false;
686
687 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
688 {
James Feist902c4c52019-04-16 14:51:31 -0700689 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700690 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700691 if (warningInterface != sensorMap.end())
692 {
693 auto &warningMap = warningInterface->second;
694
695 auto warningHigh = warningMap.find("WarningHigh");
696 auto warningLow = warningMap.find("WarningLow");
697
698 if (warningHigh != warningMap.end())
699 {
James Feist902c4c52019-04-16 14:51:31 -0700700
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700701 double value =
702 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700703 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700704 value, mValue, rExp, bValue, bExp, bSigned);
705 }
706 if (warningLow != warningMap.end())
707 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700708 double value =
709 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700710 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700711 value, mValue, rExp, bValue, bExp, bSigned);
712 }
713 }
714 if (criticalInterface != sensorMap.end())
715 {
716 auto &criticalMap = criticalInterface->second;
717
718 auto criticalHigh = criticalMap.find("CriticalHigh");
719 auto criticalLow = criticalMap.find("CriticalLow");
720
721 if (criticalHigh != criticalMap.end())
722 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700723 double value =
724 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700725 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700726 value, mValue, rExp, bValue, bExp, bSigned);
727 }
728 if (criticalLow != criticalMap.end())
729 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700730 double value =
731 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700732 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700733 value, mValue, rExp, bValue, bExp, bSigned);
734 }
735 }
736 }
James Feist902c4c52019-04-16 14:51:31 -0700737 return resp;
738}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700739
James Feist902c4c52019-04-16 14:51:31 -0700740ipmi::RspType<uint8_t, // readable
741 uint8_t, // lowerNCrit
742 uint8_t, // lowerCrit
743 uint8_t, // lowerNrecoverable
744 uint8_t, // upperNC
745 uint8_t, // upperCrit
746 uint8_t> // upperNRecoverable
747 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
748{
749 std::string connection;
750 std::string path;
751
752 auto status = getSensorConnection(sensorNumber, connection, path);
753 if (status)
754 {
755 return ipmi::response(status);
756 }
757
758 SensorMap sensorMap;
759 if (!getSensorMap(connection, path, sensorMap))
760 {
761 return ipmi::responseResponseError();
762 }
763
764 IPMIThresholds thresholdData;
765 try
766 {
767 thresholdData = getIPMIThresholds(sensorMap);
768 }
769 catch (std::exception &)
770 {
771 return ipmi::responseResponseError();
772 }
773
774 uint8_t readable = 0;
775 uint8_t lowerNC = 0;
776 uint8_t lowerCritical = 0;
777 uint8_t lowerNonRecoverable = 0;
778 uint8_t upperNC = 0;
779 uint8_t upperCritical = 0;
780 uint8_t upperNonRecoverable = 0;
781
782 if (thresholdData.warningHigh)
783 {
784 readable |=
785 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
786 upperNC = *thresholdData.warningHigh;
787 }
788 if (thresholdData.warningLow)
789 {
790 readable |=
791 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
792 lowerNC = *thresholdData.warningLow;
793 }
794
795 if (thresholdData.criticalHigh)
796 {
797 readable |=
798 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
799 upperCritical = *thresholdData.criticalHigh;
800 }
801 if (thresholdData.criticalLow)
802 {
803 readable |=
804 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
805 lowerCritical = *thresholdData.criticalLow;
806 }
807
808 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
809 lowerNonRecoverable, upperNC, upperCritical,
810 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700811}
812
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000813/** @brief implements the get Sensor event enable command
814 * @param sensorNumber - sensor number
815 *
816 * @returns IPMI completion code plus response data
817 * - enabled - Sensor Event messages
818 * - assertionEnabledLsb - Assertion event messages
819 * - assertionEnabledMsb - Assertion event messages
820 * - deassertionEnabledLsb - Deassertion event messages
821 * - deassertionEnabledMsb - Deassertion event messages
822 */
823
824ipmi::RspType<uint8_t, // enabled
825 uint8_t, // assertionEnabledLsb
826 uint8_t, // assertionEnabledMsb
827 uint8_t, // deassertionEnabledLsb
828 uint8_t> // deassertionEnabledMsb
829 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700830{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700831 std::string connection;
832 std::string path;
833
Patrick Venturea41714c2019-09-25 16:59:41 -0700834 uint8_t enabled = 0;
835 uint8_t assertionEnabledLsb = 0;
836 uint8_t assertionEnabledMsb = 0;
837 uint8_t deassertionEnabledLsb = 0;
838 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000839
840 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700841 if (status)
842 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000843 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700844 }
845
846 SensorMap sensorMap;
847 if (!getSensorMap(connection, path, sensorMap))
848 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000849 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700850 }
851
852 auto warningInterface =
853 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
854 auto criticalInterface =
855 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700856 if ((warningInterface != sensorMap.end()) ||
857 (criticalInterface != sensorMap.end()))
858 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000859 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700860 IPMISensorEventEnableByte2::sensorScanningEnable);
861 if (warningInterface != sensorMap.end())
862 {
863 auto &warningMap = warningInterface->second;
864
865 auto warningHigh = warningMap.find("WarningHigh");
866 auto warningLow = warningMap.find("WarningLow");
867 if (warningHigh != warningMap.end())
868 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000869 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700870 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000871 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700872 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
873 }
874 if (warningLow != warningMap.end())
875 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000876 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700877 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000878 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700879 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
880 }
881 }
882 if (criticalInterface != sensorMap.end())
883 {
884 auto &criticalMap = criticalInterface->second;
885
886 auto criticalHigh = criticalMap.find("CriticalHigh");
887 auto criticalLow = criticalMap.find("CriticalLow");
888
889 if (criticalHigh != criticalMap.end())
890 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000891 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700892 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000893 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700894 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
895 }
896 if (criticalLow != criticalMap.end())
897 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000898 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700899 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000900 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700901 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
902 }
903 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700904 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000905
906 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
907 assertionEnabledMsb, deassertionEnabledLsb,
908 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700909}
910
911ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
912 ipmi_request_t request,
913 ipmi_response_t response,
914 ipmi_data_len_t dataLen,
915 ipmi_context_t context)
916{
917 if (*dataLen != 1)
918 {
919 *dataLen = 0;
920 return IPMI_CC_REQ_DATA_LEN_INVALID;
921 }
922 *dataLen = 0; // default to 0 in case of an error
923
924 uint8_t sensnum = *(static_cast<uint8_t *>(request));
925
926 std::string connection;
927 std::string path;
928
929 auto status = getSensorConnection(sensnum, connection, path);
930 if (status)
931 {
932 return status;
933 }
934
935 SensorMap sensorMap;
936 if (!getSensorMap(connection, path, sensorMap))
937 {
938 return IPMI_CC_RESPONSE_ERROR;
939 }
940
941 auto warningInterface =
942 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
943 auto criticalInterface =
944 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
945
946 // zero out response buff
947 auto responseClear = static_cast<uint8_t *>(response);
948 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
949 auto resp = static_cast<SensorEventStatusResp *>(response);
950 resp->enabled =
951 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
952
James Feist392786a2019-03-19 13:36:10 -0700953 std::optional<bool> criticalDeassertHigh =
954 thresholdDeassertMap[path]["CriticalAlarmHigh"];
955 std::optional<bool> criticalDeassertLow =
956 thresholdDeassertMap[path]["CriticalAlarmLow"];
957 std::optional<bool> warningDeassertHigh =
958 thresholdDeassertMap[path]["WarningAlarmHigh"];
959 std::optional<bool> warningDeassertLow =
960 thresholdDeassertMap[path]["WarningAlarmLow"];
961
962 if (criticalDeassertHigh && !*criticalDeassertHigh)
963 {
964 resp->deassertionsMSB |= static_cast<uint8_t>(
965 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
966 }
967 if (criticalDeassertLow && !*criticalDeassertLow)
968 {
969 resp->deassertionsMSB |= static_cast<uint8_t>(
970 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
971 }
972 if (warningDeassertHigh && !*warningDeassertHigh)
973 {
974 resp->deassertionsLSB |= static_cast<uint8_t>(
975 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
976 }
977 if (warningDeassertLow && !*warningDeassertLow)
978 {
979 resp->deassertionsLSB |= static_cast<uint8_t>(
980 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
981 }
982
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700983 if ((warningInterface != sensorMap.end()) ||
984 (criticalInterface != sensorMap.end()))
985 {
986 resp->enabled = static_cast<uint8_t>(
987 IPMISensorEventEnableByte2::eventMessagesEnable);
988 if (warningInterface != sensorMap.end())
989 {
990 auto &warningMap = warningInterface->second;
991
992 auto warningHigh = warningMap.find("WarningAlarmHigh");
993 auto warningLow = warningMap.find("WarningAlarmLow");
994 auto warningHighAlarm = false;
995 auto warningLowAlarm = false;
996
997 if (warningHigh != warningMap.end())
998 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700999 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001000 }
1001 if (warningLow != warningMap.end())
1002 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001003 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001004 }
1005 if (warningHighAlarm)
1006 {
1007 resp->assertionsLSB |= static_cast<uint8_t>(
1008 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1009 }
1010 if (warningLowAlarm)
1011 {
1012 resp->assertionsLSB |= 1; // lower nc going low
1013 }
1014 }
1015 if (criticalInterface != sensorMap.end())
1016 {
1017 auto &criticalMap = criticalInterface->second;
1018
1019 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1020 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1021 auto criticalHighAlarm = false;
1022 auto criticalLowAlarm = false;
1023
1024 if (criticalHigh != criticalMap.end())
1025 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001026 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001027 }
1028 if (criticalLow != criticalMap.end())
1029 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001030 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001031 }
1032 if (criticalHighAlarm)
1033 {
1034 resp->assertionsMSB |= static_cast<uint8_t>(
1035 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1036 }
1037 if (criticalLowAlarm)
1038 {
1039 resp->assertionsLSB |= static_cast<uint8_t>(
1040 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1041 }
1042 }
1043 *dataLen = sizeof(SensorEventStatusResp);
1044 }
1045
1046 // no thresholds enabled, don't need assertionMSB
1047 else
1048 {
1049 *dataLen = sizeof(SensorEventStatusResp) - 1;
1050 }
1051
1052 return IPMI_CC_OK;
1053}
1054
1055/* end sensor commands */
1056
1057/* storage commands */
1058
James Feist74c50c62019-08-14 14:18:41 -07001059ipmi::RspType<uint8_t, // sdr version
1060 uint16_t, // record count
1061 uint16_t, // free space
1062 uint32_t, // most recent addition
1063 uint32_t, // most recent erase
1064 uint8_t // operationSupport
1065 >
1066 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001067{
James Feist74c50c62019-08-14 14:18:41 -07001068 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001069 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1070 {
James Feist74c50c62019-08-14 14:18:41 -07001071 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001072 }
1073
James Feist74c50c62019-08-14 14:18:41 -07001074 size_t fruCount = 0;
1075 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1076 if (ret != ipmi::ccSuccess)
1077 {
1078 return ipmi::response(ret);
1079 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001080
James Feist74c50c62019-08-14 14:18:41 -07001081 uint16_t recordCount =
1082 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001083
James Feist74c50c62019-08-14 14:18:41 -07001084 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001085 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001086
1087 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001088 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001089 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001090 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001091 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1092 unspecifiedFreeSpace, sdrLastAdd,
1093 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001094}
1095
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001096/** @brief implements the get SDR allocation info command
1097 *
1098 * @returns IPMI completion code plus response data
1099 * - allocUnits - Number of possible allocation units
1100 * - allocUnitSize - Allocation unit size in bytes.
1101 * - allocUnitFree - Number of free allocation units
1102 * - allocUnitLargestFree - Largest free block in allocation units
1103 * - maxRecordSize - Maximum record size in allocation units.
1104 */
1105ipmi::RspType<uint16_t, // allocUnits
1106 uint16_t, // allocUnitSize
1107 uint16_t, // allocUnitFree
1108 uint16_t, // allocUnitLargestFree
1109 uint8_t // maxRecordSize
1110 >
1111 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001112{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001113 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001114 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001115
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001116 constexpr uint16_t allocUnitFree = 0;
1117 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001119 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001121 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1122 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001123}
1124
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001125/** @brief implements the reserve SDR command
1126 * @returns IPMI completion code plus response data
1127 * - sdrReservationID
1128 */
1129ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001130{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001131 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001132 if (sdrReservationID == 0)
1133 {
1134 sdrReservationID++;
1135 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001136
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001137 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001138}
1139
James Feistb49a98a2019-04-16 13:48:09 -07001140ipmi::RspType<uint16_t, // next record ID
1141 std::vector<uint8_t> // payload
1142 >
1143 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1144 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001145{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001146 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001147
1148 // reservation required for partial reads with non zero offset into
1149 // record
James Feistb49a98a2019-04-16 13:48:09 -07001150 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001151 {
James Feistb49a98a2019-04-16 13:48:09 -07001152 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153 }
1154
1155 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1156 {
James Feistb49a98a2019-04-16 13:48:09 -07001157 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001158 }
1159
1160 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001161 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1162 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001163 {
James Feistb49a98a2019-04-16 13:48:09 -07001164 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001165 }
1166
James Feist74c50c62019-08-14 14:18:41 -07001167 size_t lastRecord =
1168 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001169 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001170 {
James Feistb49a98a2019-04-16 13:48:09 -07001171 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001172 }
James Feistb49a98a2019-04-16 13:48:09 -07001173 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001174 {
James Feistb49a98a2019-04-16 13:48:09 -07001175 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001176 }
1177
James Feistb49a98a2019-04-16 13:48:09 -07001178 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001179
James Feistb49a98a2019-04-16 13:48:09 -07001180 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001181 {
James Feist74c50c62019-08-14 14:18:41 -07001182 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001183 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001184 if (fruIndex >= fruCount)
1185 {
James Feist74c50c62019-08-14 14:18:41 -07001186 // handle type 12 hardcoded records
1187 size_t type12Index = fruIndex - fruCount;
1188 if (type12Index >= ipmi::storage::type12Count ||
1189 offset > sizeof(Type12Record))
1190 {
1191 return ipmi::responseInvalidFieldRequest();
1192 }
1193 std::vector<uint8_t> record =
1194 ipmi::storage::getType12SDRs(type12Index, recordID);
1195 if (record.size() < (offset + bytesToRead))
1196 {
1197 bytesToRead = record.size() - offset;
1198 }
James Feistb49a98a2019-04-16 13:48:09 -07001199
James Feist74c50c62019-08-14 14:18:41 -07001200 recordData.insert(recordData.end(), record.begin() + offset,
1201 record.begin() + offset + bytesToRead);
1202 }
1203 else
1204 {
1205 // handle fru records
1206 get_sdr::SensorDataFruRecord data;
1207 if (offset > sizeof(data))
1208 {
1209 return ipmi::responseInvalidFieldRequest();
1210 }
1211 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1212 if (ret != IPMI_CC_OK)
1213 {
1214 return ipmi::response(ret);
1215 }
1216 data.header.record_id_msb = recordID << 8;
1217 data.header.record_id_lsb = recordID & 0xFF;
1218 if (sizeof(data) < (offset + bytesToRead))
1219 {
1220 bytesToRead = sizeof(data) - offset;
1221 }
1222
1223 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1224 recordData.insert(recordData.end(), respStart,
1225 respStart + bytesToRead);
1226 }
James Feistb49a98a2019-04-16 13:48:09 -07001227
1228 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001229 }
1230
1231 std::string connection;
1232 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001233 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001234 for (const auto &sensor : sensorTree)
1235 {
1236 if (sensorIndex-- == 0)
1237 {
1238 if (!sensor.second.size())
1239 {
James Feistb49a98a2019-04-16 13:48:09 -07001240 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001241 }
1242 connection = sensor.second.begin()->first;
1243 path = sensor.first;
1244 break;
1245 }
1246 }
1247
1248 SensorMap sensorMap;
1249 if (!getSensorMap(connection, path, sensorMap))
1250 {
James Feistb49a98a2019-04-16 13:48:09 -07001251 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001252 }
James Feistb49a98a2019-04-16 13:48:09 -07001253 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001254 get_sdr::SensorDataFullRecord record = {0};
1255
James Feistb49a98a2019-04-16 13:48:09 -07001256 record.header.record_id_msb = recordID << 8;
1257 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001258 record.header.sdr_version = ipmiSdrVersion;
1259 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1260 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1261 sizeof(get_sdr::SensorDataRecordHeader);
1262 record.key.owner_id = 0x20;
1263 record.key.owner_lun = 0x0;
1264 record.key.sensor_number = sensornumber;
1265
1266 record.body.entity_id = 0x0;
1267 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001268 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001269 record.body.sensor_type = getSensorTypeFromPath(path);
1270 std::string type = getSensorTypeStringFromPath(path);
1271 auto typeCstr = type.c_str();
1272 auto findUnits = sensorUnits.find(typeCstr);
1273 if (findUnits != sensorUnits.end())
1274 {
1275 record.body.sensor_units_2_base =
1276 static_cast<uint8_t>(findUnits->second);
1277 } // else default 0x0 unspecified
1278
1279 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1280
1281 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1282 if (sensorObject == sensorMap.end())
1283 {
James Feistb49a98a2019-04-16 13:48:09 -07001284 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001285 }
1286
1287 auto maxObject = sensorObject->second.find("MaxValue");
1288 auto minObject = sensorObject->second.find("MinValue");
1289 double max = 128;
1290 double min = -127;
1291 if (maxObject != sensorObject->second.end())
1292 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001293 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001294 }
1295
1296 if (minObject != sensorObject->second.end())
1297 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001298 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001299 }
1300
Yong Li1f2eb5e2019-05-23 14:07:17 +08001301 int16_t mValue = 0;
1302 int8_t rExp = 0;
1303 int16_t bValue = 0;
1304 int8_t bExp = 0;
1305 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001306
1307 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1308 {
James Feistb49a98a2019-04-16 13:48:09 -07001309 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001310 }
1311
1312 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1313 record.body.m_lsb = mValue & 0xFF;
1314
1315 // move the smallest bit of the MSB into place (bit 9)
1316 // the MSbs are bits 7:8 in m_msb_and_tolerance
1317 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1318
1319 // assign the negative
1320 if (mValue < 0)
1321 {
1322 mMsb |= (1 << 7);
1323 }
1324 record.body.m_msb_and_tolerance = mMsb;
1325
1326 record.body.b_lsb = bValue & 0xFF;
1327
1328 // move the smallest bit of the MSB into place
1329 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1330 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1331
1332 // assign the negative
1333 if (bValue < 0)
1334 {
1335 bMsb |= (1 << 7);
1336 }
1337 record.body.b_msb_and_accuracy_lsb = bMsb;
1338
1339 record.body.r_b_exponents = bExp & 0x7;
1340 if (bExp < 0)
1341 {
1342 record.body.r_b_exponents |= 1 << 3;
1343 }
1344 record.body.r_b_exponents = (rExp & 0x7) << 4;
1345 if (rExp < 0)
1346 {
1347 record.body.r_b_exponents |= 1 << 7;
1348 }
1349
1350 // todo fill out rest of units
1351 if (bSigned)
1352 {
1353 record.body.sensor_units_1 = 1 << 7;
1354 }
1355
1356 // populate sensor name from path
1357 std::string name;
1358 size_t nameStart = path.rfind("/");
1359 if (nameStart != std::string::npos)
1360 {
1361 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1362 }
1363
1364 std::replace(name.begin(), name.end(), '_', ' ');
1365 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1366 {
James Feist979a2322019-05-15 09:06:54 -07001367 // try to not truncate by replacing common words
1368 constexpr std::array<std::pair<const char *, const char *>, 2>
1369 replaceWords = {std::make_pair("Output", "Out"),
1370 std::make_pair("Input", "In")};
1371 for (const auto &[find, replace] : replaceWords)
1372 {
1373 boost::replace_all(name, find, replace);
1374 }
1375
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001376 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1377 }
1378 record.body.id_string_info = name.size();
1379 std::strncpy(record.body.id_string, name.c_str(),
1380 sizeof(record.body.id_string));
1381
James Feistc4b15bc2019-04-16 15:41:39 -07001382 IPMIThresholds thresholdData;
1383 try
1384 {
1385 thresholdData = getIPMIThresholds(sensorMap);
1386 }
1387 catch (std::exception &)
1388 {
1389 return ipmi::responseResponseError();
1390 }
1391
1392 if (thresholdData.criticalHigh)
1393 {
1394 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1395 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1396 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1397 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1398 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1399 record.body.discrete_reading_setting_mask[0] |=
1400 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1401 }
1402 if (thresholdData.warningHigh)
1403 {
1404 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1405 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1406 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1407 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1408 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1409 record.body.discrete_reading_setting_mask[0] |=
1410 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1411 }
1412 if (thresholdData.criticalLow)
1413 {
1414 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1415 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1416 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1417 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1418 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1419 record.body.discrete_reading_setting_mask[0] |=
1420 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1421 }
1422 if (thresholdData.warningLow)
1423 {
1424 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1425 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1426 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1427 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1428 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1429 record.body.discrete_reading_setting_mask[0] |=
1430 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1431 }
1432
1433 // everything that is readable is setable
1434 record.body.discrete_reading_setting_mask[1] =
1435 record.body.discrete_reading_setting_mask[0];
1436
James Feistb49a98a2019-04-16 13:48:09 -07001437 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001438 {
James Feistb49a98a2019-04-16 13:48:09 -07001439 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001440 }
1441
James Feistb49a98a2019-04-16 13:48:09 -07001442 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1443 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001444
James Feistb49a98a2019-04-16 13:48:09 -07001445 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001446}
1447/* end storage commands */
1448
1449void registerSensorFunctions()
1450{
1451 // get firmware version information
1452 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1453 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1454
1455 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001456 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1457 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001458
1459 // <Set Sensor Reading and Event Status>
1460 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001461 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001462 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1463
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001464 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001465 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1466 ipmi::sensor_event::cmdPlatformEvent,
1467 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001468
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001469 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001470 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1471 ipmi::sensor_event::cmdGetSensorReading,
1472 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001473
1474 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001475 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1476 ipmi::sensor_event::cmdGetSensorThreshold,
1477 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001478
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001479 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001480 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1481 ipmi::sensor_event::cmdSetSensorThreshold,
1482 ipmi::Privilege::Operator,
1483 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001484
1485 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001486 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1487 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001488 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001489
1490 // <Get Sensor Event Status>
1491 ipmiPrintAndRegister(NETFUN_SENSOR,
Vernon Mauery98bbf692019-09-16 11:14:59 -07001492 ipmi::sensor_event::cmdGetSensorEventStatus, nullptr,
1493 ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001494
1495 // register all storage commands for both Sensor and Storage command
1496 // versions
1497
1498 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001499 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1500 ipmi::storage::cmdGetSdrRepositoryInfo,
1501 ipmi::Privilege::User,
1502 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001503
1504 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001505 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1506 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1507 ipmi::Privilege::User,
1508 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001509
1510 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001511 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1512 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001513 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001514
Vernon Mauery98bbf692019-09-16 11:14:59 -07001515 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1516 ipmi::storage::cmdReserveSdrRepository,
1517 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001518
1519 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001520 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1521 ipmi::sensor_event::cmdGetDeviceSdr,
1522 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001523
Vernon Mauery98bbf692019-09-16 11:14:59 -07001524 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1525 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1526 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001527}
1528} // namespace ipmi