blob: 662cd45cefb32755bdeec6a94929211f04f115bb [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>
James Feist2a265d52019-04-08 11:16:27 -070023#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070024#include <ipmid/utils.hpp>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070025#include <phosphor-logging/log.hpp>
26#include <sdbusplus/bus.hpp>
27#include <sdrutils.hpp>
28#include <sensorcommands.hpp>
29#include <sensorutils.hpp>
30#include <storagecommands.hpp>
31#include <string>
32
33namespace ipmi
34{
35using ManagedObjectType =
36 std::map<sdbusplus::message::object_path,
37 std::map<std::string, std::map<std::string, DbusVariant>>>;
38
39using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
James Feist14fde842018-12-06 10:19:40 -080040namespace variant_ns = sdbusplus::message::variant_ns;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070041
42static constexpr int sensorListUpdatePeriod = 10;
43static constexpr int sensorMapUpdatePeriod = 2;
44
45constexpr size_t maxSDRTotalSize =
46 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
47constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
48
49static uint16_t sdrReservationID;
50static uint32_t sdrLastAdd = noTimestamp;
51static uint32_t sdrLastRemove = noTimestamp;
52
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053053SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070054static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
55
Jason M. Bills17add592018-11-12 14:30:12 -080056// Specify the comparison required to sort and find char* map objects
57struct CmpStr
58{
59 bool operator()(const char *a, const char *b) const
60 {
61 return std::strcmp(a, b) < 0;
62 }
63};
64const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
65 sensorUnits{{{"temperature", SensorUnits::degreesC},
66 {"voltage", SensorUnits::volts},
67 {"current", SensorUnits::amps},
68 {"fan_tach", SensorUnits::rpm},
69 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070070
71void registerSensorFunctions() __attribute__((constructor));
72static sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
73
74static sdbusplus::bus::match::match sensorAdded(
75 dbus,
76 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
77 "sensors/'",
78 [](sdbusplus::message::message &m) {
79 sensorTree.clear();
80 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
81 std::chrono::system_clock::now().time_since_epoch())
82 .count();
83 });
84
85static sdbusplus::bus::match::match sensorRemoved(
86 dbus,
87 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
88 "sensors/'",
89 [](sdbusplus::message::message &m) {
90 sensorTree.clear();
91 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
92 std::chrono::system_clock::now().time_since_epoch())
93 .count();
94 });
95
James Feist392786a2019-03-19 13:36:10 -070096// this keeps track of deassertions for sensor event status command. A
97// deasertion can only happen if an assertion was seen first.
98static boost::container::flat_map<
99 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
100 thresholdDeassertMap;
101
102static sdbusplus::bus::match::match thresholdChanged(
103 dbus,
104 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
105 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
106 [](sdbusplus::message::message &m) {
107 boost::container::flat_map<std::string, std::variant<bool, double>>
108 values;
109 m.read(std::string(), values);
110
111 auto findAssert =
112 std::find_if(values.begin(), values.end(), [](const auto &pair) {
113 return pair.first.find("Alarm") != std::string::npos;
114 });
115 if (findAssert != values.end())
116 {
117 auto ptr = std::get_if<bool>(&(findAssert->second));
118 if (ptr == nullptr)
119 {
120 phosphor::logging::log<phosphor::logging::level::ERR>(
121 "thresholdChanged: Assert non bool");
122 return;
123 }
124 if (*ptr)
125 {
126 phosphor::logging::log<phosphor::logging::level::INFO>(
127 "thresholdChanged: Assert",
128 phosphor::logging::entry("SENSOR=%s", m.get_path()));
129 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
130 }
131 else
132 {
133 auto &value =
134 thresholdDeassertMap[m.get_path()][findAssert->first];
135 if (value)
136 {
137 phosphor::logging::log<phosphor::logging::level::INFO>(
138 "thresholdChanged: deassert",
139 phosphor::logging::entry("SENSOR=%s", m.get_path()));
140 value = *ptr;
141 }
142 }
143 }
144 });
145
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700146static void
147 getSensorMaxMin(const std::map<std::string, DbusVariant> &sensorPropertyMap,
148 double &max, double &min)
149{
150 auto maxMap = sensorPropertyMap.find("MaxValue");
151 auto minMap = sensorPropertyMap.find("MinValue");
152 max = 127;
153 min = -128;
154
155 if (maxMap != sensorPropertyMap.end())
156 {
James Feist14fde842018-12-06 10:19:40 -0800157 max = variant_ns::visit(VariantToDoubleVisitor(), maxMap->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700158 }
159 if (minMap != sensorPropertyMap.end())
160 {
James Feist14fde842018-12-06 10:19:40 -0800161 min = variant_ns::visit(VariantToDoubleVisitor(), minMap->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700162 }
163}
164
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700165static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
166 SensorMap &sensorMap)
167{
168 static boost::container::flat_map<
169 std::string, std::chrono::time_point<std::chrono::steady_clock>>
170 updateTimeMap;
171
172 auto updateFind = updateTimeMap.find(sensorConnection);
173 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
174 if (updateFind != updateTimeMap.end())
175 {
176 lastUpdate = updateFind->second;
177 }
178
179 auto now = std::chrono::steady_clock::now();
180
181 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
182 .count() > sensorMapUpdatePeriod)
183 {
184 updateTimeMap[sensorConnection] = now;
185
186 auto managedObj = dbus.new_method_call(
187 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
188 "GetManagedObjects");
189
190 ManagedObjectType managedObjects;
191 try
192 {
193 auto reply = dbus.call(managedObj);
194 reply.read(managedObjects);
195 }
196 catch (sdbusplus::exception_t &)
197 {
198 phosphor::logging::log<phosphor::logging::level::ERR>(
199 "Error getting managed objects from connection",
200 phosphor::logging::entry("CONNECTION=%s",
201 sensorConnection.c_str()));
202 return false;
203 }
204
205 SensorCache[sensorConnection] = managedObjects;
206 }
207 auto connection = SensorCache.find(sensorConnection);
208 if (connection == SensorCache.end())
209 {
210 return false;
211 }
212 auto path = connection->second.find(sensorPath);
213 if (path == connection->second.end())
214 {
215 return false;
216 }
217 sensorMap = path->second;
218
219 return true;
220}
221
222/* sensor commands */
223ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
224 ipmi_request_t request,
225 ipmi_response_t response,
226 ipmi_data_len_t dataLen,
227 ipmi_context_t context)
228{
229 *dataLen = 0;
230 printCommand(+netfn, +cmd);
231 return IPMI_CC_INVALID;
232}
233
James Feist0cd014a2019-04-08 15:04:33 -0700234ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
235 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700236{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700237 std::string connection;
238 std::string path;
239
240 auto status = getSensorConnection(sensnum, connection, path);
241 if (status)
242 {
James Feist0cd014a2019-04-08 15:04:33 -0700243 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700244 }
245
246 SensorMap sensorMap;
247 if (!getSensorMap(connection, path, sensorMap))
248 {
James Feist0cd014a2019-04-08 15:04:33 -0700249 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700250 }
251 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
252
253 if (sensorObject == sensorMap.end() ||
254 sensorObject->second.find("Value") == sensorObject->second.end())
255 {
James Feist0cd014a2019-04-08 15:04:33 -0700256 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700257 }
James Feist0cd014a2019-04-08 15:04:33 -0700258 auto &valueVariant = sensorObject->second["Value"];
259 double reading = variant_ns::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700260
261 double max;
262 double min;
263 getSensorMaxMin(sensorObject->second, max, min);
264
265 int16_t mValue = 0;
266 int16_t bValue = 0;
267 int8_t rExp = 0;
268 int8_t bExp = 0;
269 bool bSigned = false;
270
271 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
272 {
James Feist0cd014a2019-04-08 15:04:33 -0700273 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700274 }
275
James Feist0cd014a2019-04-08 15:04:33 -0700276 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700277 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700278 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700279 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700280 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800281 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700282
James Feist0cd014a2019-04-08 15:04:33 -0700283 uint8_t thresholds = 0;
284
285 auto warningObject =
286 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
287 if (warningObject != sensorMap.end())
288 {
289 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
290 auto alarmLow = warningObject->second.find("WarningAlarmLow");
291 if (alarmHigh != warningObject->second.end())
292 {
293 if (std::get<bool>(alarmHigh->second))
294 {
295 thresholds |= static_cast<uint8_t>(
296 IPMISensorReadingByte3::upperNonCritical);
297 }
298 }
299 if (alarmLow != warningObject->second.end())
300 {
301 if (std::get<bool>(alarmLow->second))
302 {
303 thresholds |= static_cast<uint8_t>(
304 IPMISensorReadingByte3::lowerNonCritical);
305 }
306 }
307 }
308
309 auto criticalObject =
310 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
311 if (criticalObject != sensorMap.end())
312 {
313 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
314 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
315 if (alarmHigh != criticalObject->second.end())
316 {
317 if (std::get<bool>(alarmHigh->second))
318 {
319 thresholds |=
320 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
321 }
322 }
323 if (alarmLow != criticalObject->second.end())
324 {
325 if (std::get<bool>(alarmLow->second))
326 {
327 thresholds |=
328 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
329 }
330 }
331 }
332
333 // no discrete as of today so optional byte is never returned
334 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700335}
336
337ipmi_ret_t ipmiSenSetSensorThresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
338 ipmi_request_t request,
339 ipmi_response_t response,
340 ipmi_data_len_t dataLen,
341 ipmi_context_t context)
342{
343 if (*dataLen != 8)
344 {
345 *dataLen = 0;
346 return IPMI_CC_REQ_DATA_LEN_INVALID;
347 }
348 *dataLen = 0;
349
350 SensorThresholdReq *req = static_cast<SensorThresholdReq *>(request);
351
352 // upper two bits reserved
353 if (req->mask & 0xC0)
354 {
355 return IPMI_CC_INVALID_FIELD_REQUEST;
356 }
357
358 // lower nc and upper nc not suppported on any sensor
359 if ((req->mask & static_cast<uint8_t>(
360 SensorThresholdReqEnable::setLowerNonRecoverable)) ||
361 (req->mask & static_cast<uint8_t>(
362 SensorThresholdReqEnable::setUpperNonRecoverable)))
363 {
364 return IPMI_CC_INVALID_FIELD_REQUEST;
365 }
366
367 // if no bits are set in the mask, nothing to do
368 if (!(req->mask))
369 {
370 return IPMI_CC_OK;
371 }
372
373 std::string connection;
374 std::string path;
375
376 ipmi_ret_t status = getSensorConnection(req->sensorNum, connection, path);
377 if (status)
378 {
379 return status;
380 }
381 SensorMap sensorMap;
382 if (!getSensorMap(connection, path, sensorMap))
383 {
384 return IPMI_CC_RESPONSE_ERROR;
385 }
386
387 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
388
389 if (sensorObject == sensorMap.end())
390 {
391 return IPMI_CC_RESPONSE_ERROR;
392 }
393 double max = 0;
394 double min = 0;
395 getSensorMaxMin(sensorObject->second, max, min);
396
397 int16_t mValue = 0;
398 int16_t bValue = 0;
399 int8_t rExp = 0;
400 int8_t bExp = 0;
401 bool bSigned = false;
402
403 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
404 {
405 return IPMI_CC_RESPONSE_ERROR;
406 }
407
408 bool setLowerCritical =
409 req->mask &
410 static_cast<uint8_t>(SensorThresholdReqEnable::setLowerCritical);
411 bool setUpperCritical =
412 req->mask &
413 static_cast<uint8_t>(SensorThresholdReqEnable::setUpperCritical);
414
415 bool setLowerWarning =
416 req->mask &
417 static_cast<uint8_t>(SensorThresholdReqEnable::setLowerNonCritical);
418 bool setUpperWarning =
419 req->mask &
420 static_cast<uint8_t>(SensorThresholdReqEnable::setUpperNonCritical);
421
422 // store a vector of property name, value to set, and interface
423 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
424
425 // define the indexes of the tuple
426 constexpr uint8_t propertyName = 0;
427 constexpr uint8_t thresholdValue = 1;
428 constexpr uint8_t interface = 2;
429 // verifiy all needed fields are present
430 if (setLowerCritical || setUpperCritical)
431 {
432 auto findThreshold =
433 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
434 if (findThreshold == sensorMap.end())
435 {
436 return IPMI_CC_INVALID_FIELD_REQUEST;
437 }
438 if (setLowerCritical)
439 {
440 auto findLower = findThreshold->second.find("CriticalLow");
441 if (findLower == findThreshold->second.end())
442 {
443 return IPMI_CC_INVALID_FIELD_REQUEST;
444 }
445 thresholdsToSet.emplace_back("CriticalLow", req->lowerCritical,
446 findThreshold->first);
447 }
448 if (setUpperCritical)
449 {
450 auto findUpper = findThreshold->second.find("CriticalHigh");
451 if (findUpper == findThreshold->second.end())
452 {
453 return IPMI_CC_INVALID_FIELD_REQUEST;
454 }
455 thresholdsToSet.emplace_back("CriticalHigh", req->upperCritical,
456 findThreshold->first);
457 }
458 }
459 if (setLowerWarning || setUpperWarning)
460 {
461 auto findThreshold =
462 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
463 if (findThreshold == sensorMap.end())
464 {
465 return IPMI_CC_INVALID_FIELD_REQUEST;
466 }
467 if (setLowerWarning)
468 {
469 auto findLower = findThreshold->second.find("WarningLow");
470 if (findLower == findThreshold->second.end())
471 {
472 return IPMI_CC_INVALID_FIELD_REQUEST;
473 }
474 thresholdsToSet.emplace_back("WarningLow", req->lowerNonCritical,
475 findThreshold->first);
476 }
477 if (setUpperWarning)
478 {
479 auto findUpper = findThreshold->second.find("WarningHigh");
480 if (findUpper == findThreshold->second.end())
481 {
482 return IPMI_CC_INVALID_FIELD_REQUEST;
483 }
484 thresholdsToSet.emplace_back("WarningHigh", req->upperNonCritical,
485 findThreshold->first);
486 }
487 }
488
489 for (const auto &property : thresholdsToSet)
490 {
491 // from section 36.3 in the IPMI Spec, assume all linear
492 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
493 (bValue * std::pow(10, bExp))) *
494 std::pow(10, rExp);
495 setDbusProperty(dbus, connection, path, std::get<interface>(property),
496 std::get<propertyName>(property),
497 ipmi::Value(valueToSet));
498 }
499
500 return IPMI_CC_OK;
501}
502
503ipmi_ret_t ipmiSenGetSensorThresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
504 ipmi_request_t request,
505 ipmi_response_t response,
506 ipmi_data_len_t dataLen,
507 ipmi_context_t context)
508{
509 if (*dataLen != 1)
510 {
511 *dataLen = 0;
512 return IPMI_CC_REQ_DATA_LEN_INVALID;
513 }
514 *dataLen = 0; // default to 0 in case of an error
515
516 uint8_t sensnum = *(static_cast<uint8_t *>(request));
517
518 std::string connection;
519 std::string path;
520
521 auto status = getSensorConnection(sensnum, connection, path);
522 if (status)
523 {
524 return status;
525 }
526
527 SensorMap sensorMap;
528 if (!getSensorMap(connection, path, sensorMap))
529 {
530 return IPMI_CC_RESPONSE_ERROR;
531 }
532
533 // zero out response buff
534 auto responseClear = static_cast<uint8_t *>(response);
535 std::fill(responseClear, responseClear + sizeof(SensorThresholdResp), 0);
536
537 auto warningInterface =
538 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
539 auto criticalInterface =
540 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
541
542 if ((warningInterface != sensorMap.end()) ||
543 (criticalInterface != sensorMap.end()))
544 {
545 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
546
547 if (sensorPair == sensorMap.end())
548 {
549 // should not have been able to find a sensor not implementing
550 // the sensor object
551 return IPMI_CC_RESPONSE_ERROR;
552 }
553
554 double max;
555 double min;
556 getSensorMaxMin(sensorPair->second, max, min);
557
558 int16_t mValue = 0;
559 int16_t bValue = 0;
560 int8_t rExp = 0;
561 int8_t bExp = 0;
562 bool bSigned = false;
563
564 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
565 {
566 return IPMI_CC_RESPONSE_ERROR;
567 }
568
569 auto msgReply = static_cast<SensorThresholdResp *>(response);
570
571 if (warningInterface != sensorMap.end())
572 {
573 auto &warningMap = warningInterface->second;
574
575 auto warningHigh = warningMap.find("WarningHigh");
576 auto warningLow = warningMap.find("WarningLow");
577
578 if (warningHigh != warningMap.end())
579 {
580 msgReply->readable |=
581 1 << static_cast<int>(
582 IPMIhresholdRespBits::upperNonCritical);
James Feist14fde842018-12-06 10:19:40 -0800583 double value = variant_ns::visit(VariantToDoubleVisitor(),
584 warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700585 msgReply->uppernc = scaleIPMIValueFromDouble(
586 value, mValue, rExp, bValue, bExp, bSigned);
587 }
588 if (warningLow != warningMap.end())
589 {
590 msgReply->readable |=
591 1 << static_cast<int>(
592 IPMIhresholdRespBits::lowerNonCritical);
James Feist14fde842018-12-06 10:19:40 -0800593 double value = variant_ns::visit(VariantToDoubleVisitor(),
594 warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700595 msgReply->lowernc = scaleIPMIValueFromDouble(
596 value, mValue, rExp, bValue, bExp, bSigned);
597 }
598 }
599 if (criticalInterface != sensorMap.end())
600 {
601 auto &criticalMap = criticalInterface->second;
602
603 auto criticalHigh = criticalMap.find("CriticalHigh");
604 auto criticalLow = criticalMap.find("CriticalLow");
605
606 if (criticalHigh != criticalMap.end())
607 {
608 msgReply->readable |=
609 1 << static_cast<int>(IPMIhresholdRespBits::upperCritical);
James Feist14fde842018-12-06 10:19:40 -0800610 double value = variant_ns::visit(VariantToDoubleVisitor(),
611 criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700612 msgReply->uppercritical = scaleIPMIValueFromDouble(
613 value, mValue, rExp, bValue, bExp, bSigned);
614 }
615 if (criticalLow != criticalMap.end())
616 {
617 msgReply->readable |=
618 1 << static_cast<int>(IPMIhresholdRespBits::lowerCritical);
James Feist14fde842018-12-06 10:19:40 -0800619 double value = variant_ns::visit(VariantToDoubleVisitor(),
620 criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700621 msgReply->lowercritical = scaleIPMIValueFromDouble(
622 value, mValue, rExp, bValue, bExp, bSigned);
623 }
624 }
625 }
626
627 *dataLen = sizeof(SensorThresholdResp);
628 return IPMI_CC_OK;
629}
630
631ipmi_ret_t ipmiSenGetSensorEventEnable(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
632 ipmi_request_t request,
633 ipmi_response_t response,
634 ipmi_data_len_t dataLen,
635 ipmi_context_t context)
636{
637 if (*dataLen != 1)
638 {
639 *dataLen = 0;
640 return IPMI_CC_REQ_DATA_LEN_INVALID;
641 }
642 *dataLen = 0; // default to 0 in case of an error
643
644 uint8_t sensnum = *(static_cast<uint8_t *>(request));
645
646 std::string connection;
647 std::string path;
648
649 auto status = getSensorConnection(sensnum, connection, path);
650 if (status)
651 {
652 return status;
653 }
654
655 SensorMap sensorMap;
656 if (!getSensorMap(connection, path, sensorMap))
657 {
658 return IPMI_CC_RESPONSE_ERROR;
659 }
660
661 auto warningInterface =
662 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
663 auto criticalInterface =
664 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
665
666 if ((warningInterface != sensorMap.end()) ||
667 (criticalInterface != sensorMap.end()))
668 {
669 // zero out response buff
670 auto responseClear = static_cast<uint8_t *>(response);
671 std::fill(responseClear, responseClear + sizeof(SensorEventEnableResp),
672 0);
673
674 // assume all threshold sensors
675 auto resp = static_cast<SensorEventEnableResp *>(response);
676
677 resp->enabled = static_cast<uint8_t>(
678 IPMISensorEventEnableByte2::sensorScanningEnable);
679 if (warningInterface != sensorMap.end())
680 {
681 auto &warningMap = warningInterface->second;
682
683 auto warningHigh = warningMap.find("WarningHigh");
684 auto warningLow = warningMap.find("WarningLow");
685 if (warningHigh != warningMap.end())
686 {
687 resp->assertionEnabledLSB |= static_cast<uint8_t>(
688 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
689 resp->deassertionEnabledLSB |= static_cast<uint8_t>(
690 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
691 }
692 if (warningLow != warningMap.end())
693 {
694 resp->assertionEnabledLSB |= static_cast<uint8_t>(
695 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
696 resp->deassertionEnabledLSB |= static_cast<uint8_t>(
697 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
698 }
699 }
700 if (criticalInterface != sensorMap.end())
701 {
702 auto &criticalMap = criticalInterface->second;
703
704 auto criticalHigh = criticalMap.find("CriticalHigh");
705 auto criticalLow = criticalMap.find("CriticalLow");
706
707 if (criticalHigh != criticalMap.end())
708 {
709 resp->assertionEnabledMSB |= static_cast<uint8_t>(
710 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
711 resp->deassertionEnabledMSB |= static_cast<uint8_t>(
712 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
713 }
714 if (criticalLow != criticalMap.end())
715 {
716 resp->assertionEnabledLSB |= static_cast<uint8_t>(
717 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
718 resp->deassertionEnabledLSB |= static_cast<uint8_t>(
719 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
720 }
721 }
722 *dataLen =
723 sizeof(SensorEventEnableResp); // todo only return needed bytes
724 }
725 // no thresholds enabled
726 else
727 {
728 *dataLen = 1;
729 auto resp = static_cast<uint8_t *>(response);
730 *resp = static_cast<uint8_t>(
731 IPMISensorEventEnableByte2::eventMessagesEnable);
732 *resp |= static_cast<uint8_t>(
733 IPMISensorEventEnableByte2::sensorScanningEnable);
734 }
735 return IPMI_CC_OK;
736}
737
738ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
739 ipmi_request_t request,
740 ipmi_response_t response,
741 ipmi_data_len_t dataLen,
742 ipmi_context_t context)
743{
744 if (*dataLen != 1)
745 {
746 *dataLen = 0;
747 return IPMI_CC_REQ_DATA_LEN_INVALID;
748 }
749 *dataLen = 0; // default to 0 in case of an error
750
751 uint8_t sensnum = *(static_cast<uint8_t *>(request));
752
753 std::string connection;
754 std::string path;
755
756 auto status = getSensorConnection(sensnum, connection, path);
757 if (status)
758 {
759 return status;
760 }
761
762 SensorMap sensorMap;
763 if (!getSensorMap(connection, path, sensorMap))
764 {
765 return IPMI_CC_RESPONSE_ERROR;
766 }
767
768 auto warningInterface =
769 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
770 auto criticalInterface =
771 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
772
773 // zero out response buff
774 auto responseClear = static_cast<uint8_t *>(response);
775 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
776 auto resp = static_cast<SensorEventStatusResp *>(response);
777 resp->enabled =
778 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
779
James Feist392786a2019-03-19 13:36:10 -0700780 std::optional<bool> criticalDeassertHigh =
781 thresholdDeassertMap[path]["CriticalAlarmHigh"];
782 std::optional<bool> criticalDeassertLow =
783 thresholdDeassertMap[path]["CriticalAlarmLow"];
784 std::optional<bool> warningDeassertHigh =
785 thresholdDeassertMap[path]["WarningAlarmHigh"];
786 std::optional<bool> warningDeassertLow =
787 thresholdDeassertMap[path]["WarningAlarmLow"];
788
789 if (criticalDeassertHigh && !*criticalDeassertHigh)
790 {
791 resp->deassertionsMSB |= static_cast<uint8_t>(
792 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
793 }
794 if (criticalDeassertLow && !*criticalDeassertLow)
795 {
796 resp->deassertionsMSB |= static_cast<uint8_t>(
797 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
798 }
799 if (warningDeassertHigh && !*warningDeassertHigh)
800 {
801 resp->deassertionsLSB |= static_cast<uint8_t>(
802 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
803 }
804 if (warningDeassertLow && !*warningDeassertLow)
805 {
806 resp->deassertionsLSB |= static_cast<uint8_t>(
807 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
808 }
809
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700810 if ((warningInterface != sensorMap.end()) ||
811 (criticalInterface != sensorMap.end()))
812 {
813 resp->enabled = static_cast<uint8_t>(
814 IPMISensorEventEnableByte2::eventMessagesEnable);
815 if (warningInterface != sensorMap.end())
816 {
817 auto &warningMap = warningInterface->second;
818
819 auto warningHigh = warningMap.find("WarningAlarmHigh");
820 auto warningLow = warningMap.find("WarningAlarmLow");
821 auto warningHighAlarm = false;
822 auto warningLowAlarm = false;
823
824 if (warningHigh != warningMap.end())
825 {
James Feist880b7332018-12-06 11:14:02 -0800826 warningHighAlarm = sdbusplus::message::variant_ns::get<bool>(
827 warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700828 }
829 if (warningLow != warningMap.end())
830 {
James Feist880b7332018-12-06 11:14:02 -0800831 warningLowAlarm = sdbusplus::message::variant_ns::get<bool>(
832 warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700833 }
834 if (warningHighAlarm)
835 {
836 resp->assertionsLSB |= static_cast<uint8_t>(
837 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
838 }
839 if (warningLowAlarm)
840 {
841 resp->assertionsLSB |= 1; // lower nc going low
842 }
843 }
844 if (criticalInterface != sensorMap.end())
845 {
846 auto &criticalMap = criticalInterface->second;
847
848 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
849 auto criticalLow = criticalMap.find("CriticalAlarmLow");
850 auto criticalHighAlarm = false;
851 auto criticalLowAlarm = false;
852
853 if (criticalHigh != criticalMap.end())
854 {
James Feist880b7332018-12-06 11:14:02 -0800855 criticalHighAlarm = sdbusplus::message::variant_ns::get<bool>(
856 criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700857 }
858 if (criticalLow != criticalMap.end())
859 {
James Feist880b7332018-12-06 11:14:02 -0800860 criticalLowAlarm = sdbusplus::message::variant_ns::get<bool>(
861 criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700862 }
863 if (criticalHighAlarm)
864 {
865 resp->assertionsMSB |= static_cast<uint8_t>(
866 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
867 }
868 if (criticalLowAlarm)
869 {
870 resp->assertionsLSB |= static_cast<uint8_t>(
871 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
872 }
873 }
874 *dataLen = sizeof(SensorEventStatusResp);
875 }
876
877 // no thresholds enabled, don't need assertionMSB
878 else
879 {
880 *dataLen = sizeof(SensorEventStatusResp) - 1;
881 }
882
883 return IPMI_CC_OK;
884}
885
886/* end sensor commands */
887
888/* storage commands */
889
890ipmi_ret_t ipmiStorageGetSDRRepositoryInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
891 ipmi_request_t request,
892 ipmi_response_t response,
893 ipmi_data_len_t dataLen,
894 ipmi_context_t context)
895{
896 printCommand(+netfn, +cmd);
897
898 if (*dataLen)
899 {
900 *dataLen = 0;
901 return IPMI_CC_REQ_DATA_LEN_INVALID;
902 }
903 *dataLen = 0; // default to 0 in case of an error
904
905 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
906 {
907 return IPMI_CC_RESPONSE_ERROR;
908 }
909
910 // zero out response buff
911 auto responseClear = static_cast<uint8_t *>(response);
912 std::fill(responseClear, responseClear + sizeof(GetSDRInfoResp), 0);
913
914 auto resp = static_cast<GetSDRInfoResp *>(response);
915 resp->sdrVersion = ipmiSdrVersion;
916 uint16_t recordCount = sensorTree.size();
917
918 // todo: for now, sdr count is number of sensors
919 resp->recordCountLS = recordCount & 0xFF;
920 resp->recordCountMS = recordCount >> 8;
921
922 // free space unspcified
923 resp->freeSpace[0] = 0xFF;
924 resp->freeSpace[1] = 0xFF;
925
926 resp->mostRecentAddition = sdrLastAdd;
927 resp->mostRecentErase = sdrLastRemove;
928 resp->operationSupport = static_cast<uint8_t>(
929 SdrRepositoryInfoOps::overflow); // write not supported
930 resp->operationSupport |=
931 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
932 resp->operationSupport |= static_cast<uint8_t>(
933 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
934 *dataLen = sizeof(GetSDRInfoResp);
935 return IPMI_CC_OK;
936}
937
938ipmi_ret_t ipmiStorageGetSDRAllocationInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
939 ipmi_request_t request,
940 ipmi_response_t response,
941 ipmi_data_len_t dataLen,
942 ipmi_context_t context)
943{
944 if (*dataLen)
945 {
946 *dataLen = 0;
947 return IPMI_CC_REQ_DATA_LEN_INVALID;
948 }
949 *dataLen = 0; // default to 0 in case of an error
950 GetAllocInfoResp *resp = static_cast<GetAllocInfoResp *>(response);
951
952 // 0000h unspecified number of alloc units
953 resp->allocUnitsLSB = 0;
954 resp->allocUnitsMSB = 0;
955
956 // max unit size is size of max record
957 resp->allocUnitSizeLSB = maxSDRTotalSize & 0xFF;
958 resp->allocUnitSizeMSB = maxSDRTotalSize >> 8;
959 // read only sdr, no free alloc blocks
960 resp->allocUnitFreeLSB = 0;
961 resp->allocUnitFreeMSB = 0;
962 resp->allocUnitLargestFreeLSB = 0;
963 resp->allocUnitLargestFreeMSB = 0;
964 // only allow one block at a time
965 resp->maxRecordSize = 1;
966
967 *dataLen = sizeof(GetAllocInfoResp);
968
969 return IPMI_CC_OK;
970}
971
972ipmi_ret_t ipmiStorageReserveSDR(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
973 ipmi_request_t request,
974 ipmi_response_t response,
975 ipmi_data_len_t dataLen,
976 ipmi_context_t context)
977{
978 printCommand(+netfn, +cmd);
979
980 if (*dataLen)
981 {
982 *dataLen = 0;
983 return IPMI_CC_REQ_DATA_LEN_INVALID;
984 }
985 *dataLen = 0; // default to 0 in case of an error
986 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -0800987 if (sdrReservationID == 0)
988 {
989 sdrReservationID++;
990 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700991 *dataLen = 2;
992 auto resp = static_cast<uint8_t *>(response);
993 resp[0] = sdrReservationID & 0xFF;
994 resp[1] = sdrReservationID >> 8;
995
996 return IPMI_CC_OK;
997}
998
999ipmi_ret_t ipmiStorageGetSDR(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1000 ipmi_request_t request, ipmi_response_t response,
1001 ipmi_data_len_t dataLen, ipmi_context_t context)
1002{
1003 printCommand(+netfn, +cmd);
1004
1005 if (*dataLen != 6)
1006 {
1007 *dataLen = 0;
1008 return IPMI_CC_REQ_DATA_LEN_INVALID;
1009 }
1010 auto requestedSize = *dataLen;
1011 *dataLen = 0; // default to 0 in case of an error
1012
1013 constexpr uint16_t lastRecordIndex = 0xFFFF;
1014 auto req = static_cast<GetSDRReq *>(request);
1015
1016 // reservation required for partial reads with non zero offset into
1017 // record
James Feista80cb902019-02-14 13:05:25 -08001018 if ((sdrReservationID == 0 || req->reservationID != sdrReservationID) &&
1019 req->offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001020 {
1021 return IPMI_CC_INVALID_RESERVATION_ID;
1022 }
1023
1024 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1025 {
1026 return IPMI_CC_RESPONSE_ERROR;
1027 }
1028
1029 size_t fruCount = 0;
1030 ipmi_ret_t ret = ipmi::storage::getFruSdrCount(fruCount);
1031 if (ret != IPMI_CC_OK)
1032 {
1033 return ret;
1034 }
1035
1036 size_t lastRecord = sensorTree.size() + fruCount - 1;
1037 if (req->recordID == lastRecordIndex)
1038 {
1039 req->recordID = lastRecord;
1040 }
1041 if (req->recordID > lastRecord)
1042 {
1043 return IPMI_CC_INVALID_FIELD_REQUEST;
1044 }
1045
1046 uint16_t nextRecord =
John Wang7e7ed8b2019-03-20 10:35:02 +08001047 lastRecord > req->recordID ? req->recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001048
1049 auto responseClear = static_cast<uint8_t *>(response);
1050 std::fill(responseClear, responseClear + requestedSize, 0);
1051
1052 auto resp = static_cast<get_sdr::GetSdrResp *>(response);
1053 resp->next_record_id_lsb = nextRecord & 0xFF;
1054 resp->next_record_id_msb = nextRecord >> 8;
1055
1056 if (req->recordID >= sensorTree.size())
1057 {
1058 size_t fruIndex = req->recordID - sensorTree.size();
1059 if (fruIndex >= fruCount)
1060 {
1061 return IPMI_CC_INVALID_FIELD_REQUEST;
1062 }
1063 get_sdr::SensorDataFruRecord data;
1064 if (req->offset > sizeof(data))
1065 {
1066 return IPMI_CC_INVALID_FIELD_REQUEST;
1067 }
1068 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1069 if (ret != IPMI_CC_OK)
1070 {
1071 return ret;
1072 }
1073 data.header.record_id_msb = req->recordID << 8;
1074 data.header.record_id_lsb = req->recordID & 0xFF;
1075 if (sizeof(data) < (req->offset + req->bytesToRead))
1076 {
1077 req->bytesToRead = sizeof(data) - req->offset;
1078 }
1079 *dataLen = req->bytesToRead + 2; // next record
1080 std::memcpy(&resp->record_data, (char *)&data + req->offset,
1081 req->bytesToRead);
1082 return IPMI_CC_OK;
1083 }
1084
1085 std::string connection;
1086 std::string path;
1087 uint16_t sensorIndex = req->recordID;
1088 for (const auto &sensor : sensorTree)
1089 {
1090 if (sensorIndex-- == 0)
1091 {
1092 if (!sensor.second.size())
1093 {
1094 return IPMI_CC_RESPONSE_ERROR;
1095 }
1096 connection = sensor.second.begin()->first;
1097 path = sensor.first;
1098 break;
1099 }
1100 }
1101
1102 SensorMap sensorMap;
1103 if (!getSensorMap(connection, path, sensorMap))
1104 {
1105 return IPMI_CC_RESPONSE_ERROR;
1106 }
1107 uint8_t sensornumber = (req->recordID & 0xFF);
1108 get_sdr::SensorDataFullRecord record = {0};
1109
1110 record.header.record_id_msb = req->recordID << 8;
1111 record.header.record_id_lsb = req->recordID & 0xFF;
1112 record.header.sdr_version = ipmiSdrVersion;
1113 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1114 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1115 sizeof(get_sdr::SensorDataRecordHeader);
1116 record.key.owner_id = 0x20;
1117 record.key.owner_lun = 0x0;
1118 record.key.sensor_number = sensornumber;
1119
1120 record.body.entity_id = 0x0;
1121 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001122 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001123 record.body.sensor_type = getSensorTypeFromPath(path);
1124 std::string type = getSensorTypeStringFromPath(path);
1125 auto typeCstr = type.c_str();
1126 auto findUnits = sensorUnits.find(typeCstr);
1127 if (findUnits != sensorUnits.end())
1128 {
1129 record.body.sensor_units_2_base =
1130 static_cast<uint8_t>(findUnits->second);
1131 } // else default 0x0 unspecified
1132
1133 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1134
1135 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1136 if (sensorObject == sensorMap.end())
1137 {
1138 return IPMI_CC_RESPONSE_ERROR;
1139 }
1140
1141 auto maxObject = sensorObject->second.find("MaxValue");
1142 auto minObject = sensorObject->second.find("MinValue");
1143 double max = 128;
1144 double min = -127;
1145 if (maxObject != sensorObject->second.end())
1146 {
James Feist14fde842018-12-06 10:19:40 -08001147 max = variant_ns::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001148 }
1149
1150 if (minObject != sensorObject->second.end())
1151 {
James Feist14fde842018-12-06 10:19:40 -08001152 min = variant_ns::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153 }
1154
1155 int16_t mValue;
1156 int8_t rExp;
1157 int16_t bValue;
1158 int8_t bExp;
1159 bool bSigned;
1160
1161 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1162 {
1163 return IPMI_CC_RESPONSE_ERROR;
1164 }
1165
1166 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1167 record.body.m_lsb = mValue & 0xFF;
1168
1169 // move the smallest bit of the MSB into place (bit 9)
1170 // the MSbs are bits 7:8 in m_msb_and_tolerance
1171 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1172
1173 // assign the negative
1174 if (mValue < 0)
1175 {
1176 mMsb |= (1 << 7);
1177 }
1178 record.body.m_msb_and_tolerance = mMsb;
1179
1180 record.body.b_lsb = bValue & 0xFF;
1181
1182 // move the smallest bit of the MSB into place
1183 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1184 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1185
1186 // assign the negative
1187 if (bValue < 0)
1188 {
1189 bMsb |= (1 << 7);
1190 }
1191 record.body.b_msb_and_accuracy_lsb = bMsb;
1192
1193 record.body.r_b_exponents = bExp & 0x7;
1194 if (bExp < 0)
1195 {
1196 record.body.r_b_exponents |= 1 << 3;
1197 }
1198 record.body.r_b_exponents = (rExp & 0x7) << 4;
1199 if (rExp < 0)
1200 {
1201 record.body.r_b_exponents |= 1 << 7;
1202 }
1203
1204 // todo fill out rest of units
1205 if (bSigned)
1206 {
1207 record.body.sensor_units_1 = 1 << 7;
1208 }
1209
1210 // populate sensor name from path
1211 std::string name;
1212 size_t nameStart = path.rfind("/");
1213 if (nameStart != std::string::npos)
1214 {
1215 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1216 }
1217
1218 std::replace(name.begin(), name.end(), '_', ' ');
1219 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1220 {
1221 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1222 }
1223 record.body.id_string_info = name.size();
1224 std::strncpy(record.body.id_string, name.c_str(),
1225 sizeof(record.body.id_string));
1226
1227 if (sizeof(get_sdr::SensorDataFullRecord) <
1228 (req->offset + req->bytesToRead))
1229 {
1230 req->bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - req->offset;
1231 }
1232
1233 *dataLen =
1234 2 + req->bytesToRead; // bytesToRead + MSB and LSB of next record id
1235
1236 std::memcpy(&resp->record_data, (char *)&record + req->offset,
1237 req->bytesToRead);
1238
1239 return IPMI_CC_OK;
1240}
1241/* end storage commands */
1242
1243void registerSensorFunctions()
1244{
1245 // get firmware version information
1246 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1247 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1248
1249 // <Get Sensor Type>
1250 ipmiPrintAndRegister(
1251 NETFUN_SENSOR,
1252 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetSensorType),
1253 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
1254
1255 // <Set Sensor Reading and Event Status>
1256 ipmiPrintAndRegister(
1257 NETFUN_SENSOR,
1258 static_cast<ipmi_cmd_t>(
1259 IPMINetfnSensorCmds::ipmiCmdSetSensorReadingAndEventStatus),
1260 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1261
1262 // <Get Sensor Reading>
James Feist0cd014a2019-04-08 15:04:33 -07001263 ipmi::registerHandler(
1264 ipmi::prioOemBase, NETFUN_SENSOR,
1265 static_cast<ipmi::Cmd>(IPMINetfnSensorCmds::ipmiCmdGetSensorReading),
1266 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001267
1268 // <Get Sensor Threshold>
1269 ipmiPrintAndRegister(
1270 NETFUN_SENSOR,
1271 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetSensorThreshold),
1272 nullptr, ipmiSenGetSensorThresholds, PRIVILEGE_USER);
1273
1274 ipmiPrintAndRegister(
1275 NETFUN_SENSOR,
1276 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdSetSensorThreshold),
1277 nullptr, ipmiSenSetSensorThresholds, PRIVILEGE_OPERATOR);
1278
1279 // <Get Sensor Event Enable>
1280 ipmiPrintAndRegister(NETFUN_SENSOR,
1281 static_cast<ipmi_cmd_t>(
1282 IPMINetfnSensorCmds::ipmiCmdGetSensorEventEnable),
1283 nullptr, ipmiSenGetSensorEventEnable, PRIVILEGE_USER);
1284
1285 // <Get Sensor Event Status>
1286 ipmiPrintAndRegister(NETFUN_SENSOR,
1287 static_cast<ipmi_cmd_t>(
1288 IPMINetfnSensorCmds::ipmiCmdGetSensorEventStatus),
1289 nullptr, ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
1290
1291 // register all storage commands for both Sensor and Storage command
1292 // versions
1293
1294 // <Get SDR Repository Info>
1295 ipmiPrintAndRegister(
1296 NETFUN_STORAGE,
1297 static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetRepositoryInfo),
1298 nullptr, ipmiStorageGetSDRRepositoryInfo, PRIVILEGE_USER);
1299
1300 // <Get SDR Allocation Info>
1301 ipmiPrintAndRegister(NETFUN_STORAGE,
1302 static_cast<ipmi_cmd_t>(
1303 IPMINetfnStorageCmds::ipmiCmdGetSDRAllocationInfo),
1304 nullptr, ipmiStorageGetSDRAllocationInfo,
1305 PRIVILEGE_USER);
1306
1307 // <Reserve SDR Repo>
1308 ipmiPrintAndRegister(NETFUN_SENSOR,
1309 static_cast<ipmi_cmd_t>(
1310 IPMINetfnSensorCmds::ipmiCmdReserveDeviceSDRRepo),
1311 nullptr, ipmiStorageReserveSDR, PRIVILEGE_USER);
1312
1313 ipmiPrintAndRegister(
1314 NETFUN_STORAGE,
1315 static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdReserveSDR),
1316 nullptr, ipmiStorageReserveSDR, PRIVILEGE_USER);
1317
1318 // <Get Sdr>
1319 ipmiPrintAndRegister(
1320 NETFUN_SENSOR,
1321 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetDeviceSDR),
1322 nullptr, ipmiStorageGetSDR, PRIVILEGE_USER);
1323
1324 ipmiPrintAndRegister(
1325 NETFUN_STORAGE,
1326 static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetSDR), nullptr,
1327 ipmiStorageGetSDR, PRIVILEGE_USER);
1328 return;
1329}
1330} // namespace ipmi