blob: efd31fadd9891f941262efb4090a72db9cee7606 [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
Patrick Venture31b35d52019-10-20 13:25:16 -070017#include "sensorcommands.hpp"
18
19#include "commandutils.hpp"
20#include "ipmi_to_redfish_hooks.hpp"
21#include "sdrutils.hpp"
22#include "sensorutils.hpp"
23#include "storagecommands.hpp"
24
Patrick Venturef777e1b2019-09-25 17:45:44 -070025#include <algorithm>
Patrick Venture44ec88e2019-09-25 17:48:29 -070026#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070027#include <boost/algorithm/string.hpp>
28#include <boost/container/flat_map.hpp>
29#include <chrono>
30#include <cmath>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070031#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070032#include <iostream>
James Feist2a265d52019-04-08 11:16:27 -070033#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070034#include <ipmid/utils.hpp>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070035#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070036#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070037#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070038#include <phosphor-logging/log.hpp>
39#include <sdbusplus/bus.hpp>
Patrick Venturee6154022019-09-25 17:50:25 -070040#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070041#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070042#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070043#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070044
45namespace ipmi
46{
47using ManagedObjectType =
48 std::map<sdbusplus::message::object_path,
49 std::map<std::string, std::map<std::string, DbusVariant>>>;
50
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070051static constexpr int sensorListUpdatePeriod = 10;
52static constexpr int sensorMapUpdatePeriod = 2;
53
54constexpr size_t maxSDRTotalSize =
55 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
56constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
57
58static uint16_t sdrReservationID;
59static uint32_t sdrLastAdd = noTimestamp;
60static uint32_t sdrLastRemove = noTimestamp;
61
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053062SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070063static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
64
Jason M. Bills17add592018-11-12 14:30:12 -080065// Specify the comparison required to sort and find char* map objects
66struct CmpStr
67{
68 bool operator()(const char *a, const char *b) const
69 {
70 return std::strcmp(a, b) < 0;
71 }
72};
73const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
74 sensorUnits{{{"temperature", SensorUnits::degreesC},
75 {"voltage", SensorUnits::volts},
76 {"current", SensorUnits::amps},
77 {"fan_tach", SensorUnits::rpm},
78 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070079
80void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070081
82static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070083 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070084 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
85 "sensors/'",
86 [](sdbusplus::message::message &m) {
87 sensorTree.clear();
88 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
89 std::chrono::system_clock::now().time_since_epoch())
90 .count();
91 });
92
93static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070094 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070095 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
96 "sensors/'",
97 [](sdbusplus::message::message &m) {
98 sensorTree.clear();
99 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
100 std::chrono::system_clock::now().time_since_epoch())
101 .count();
102 });
103
James Feist392786a2019-03-19 13:36:10 -0700104// this keeps track of deassertions for sensor event status command. A
105// deasertion can only happen if an assertion was seen first.
106static boost::container::flat_map<
107 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
108 thresholdDeassertMap;
109
110static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700111 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700112 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
113 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
114 [](sdbusplus::message::message &m) {
115 boost::container::flat_map<std::string, std::variant<bool, double>>
116 values;
117 m.read(std::string(), values);
118
119 auto findAssert =
120 std::find_if(values.begin(), values.end(), [](const auto &pair) {
121 return pair.first.find("Alarm") != std::string::npos;
122 });
123 if (findAssert != values.end())
124 {
125 auto ptr = std::get_if<bool>(&(findAssert->second));
126 if (ptr == nullptr)
127 {
128 phosphor::logging::log<phosphor::logging::level::ERR>(
129 "thresholdChanged: Assert non bool");
130 return;
131 }
132 if (*ptr)
133 {
134 phosphor::logging::log<phosphor::logging::level::INFO>(
135 "thresholdChanged: Assert",
136 phosphor::logging::entry("SENSOR=%s", m.get_path()));
137 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
138 }
139 else
140 {
141 auto &value =
142 thresholdDeassertMap[m.get_path()][findAssert->first];
143 if (value)
144 {
145 phosphor::logging::log<phosphor::logging::level::INFO>(
146 "thresholdChanged: deassert",
147 phosphor::logging::entry("SENSOR=%s", m.get_path()));
148 value = *ptr;
149 }
150 }
151 }
152 });
153
James Feistaecaef72019-04-26 10:30:32 -0700154static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
155 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700156{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700157 max = 127;
158 min = -128;
159
James Feistaecaef72019-04-26 10:30:32 -0700160 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
161 auto critical =
162 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
163 auto warning =
164 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
165
166 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700167 {
James Feistaecaef72019-04-26 10:30:32 -0700168 auto maxMap = sensorObject->second.find("MaxValue");
169 auto minMap = sensorObject->second.find("MinValue");
170
171 if (maxMap != sensorObject->second.end())
172 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700173 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700174 }
175 if (minMap != sensorObject->second.end())
176 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700177 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700178 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700179 }
James Feistaecaef72019-04-26 10:30:32 -0700180 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700181 {
James Feistaecaef72019-04-26 10:30:32 -0700182 auto lower = critical->second.find("CriticalLow");
183 auto upper = critical->second.find("CriticalHigh");
184 if (lower != critical->second.end())
185 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700186 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700187 min = std::min(value, min);
188 }
189 if (upper != critical->second.end())
190 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700191 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700192 max = std::max(value, max);
193 }
194 }
195 if (warning != sensorMap.end())
196 {
197
198 auto lower = warning->second.find("WarningLow");
199 auto upper = warning->second.find("WarningHigh");
200 if (lower != warning->second.end())
201 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700202 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700203 min = std::min(value, min);
204 }
205 if (upper != warning->second.end())
206 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700207 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700208 max = std::max(value, max);
209 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700210 }
211}
212
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700213static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
214 SensorMap &sensorMap)
215{
216 static boost::container::flat_map<
217 std::string, std::chrono::time_point<std::chrono::steady_clock>>
218 updateTimeMap;
219
220 auto updateFind = updateTimeMap.find(sensorConnection);
221 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
222 if (updateFind != updateTimeMap.end())
223 {
224 lastUpdate = updateFind->second;
225 }
226
227 auto now = std::chrono::steady_clock::now();
228
229 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
230 .count() > sensorMapUpdatePeriod)
231 {
232 updateTimeMap[sensorConnection] = now;
233
Vernon Mauery15419dd2019-05-24 09:40:30 -0700234 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
235 auto managedObj = dbus->new_method_call(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700236 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
237 "GetManagedObjects");
238
239 ManagedObjectType managedObjects;
240 try
241 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700242 auto reply = dbus->call(managedObj);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700243 reply.read(managedObjects);
244 }
245 catch (sdbusplus::exception_t &)
246 {
247 phosphor::logging::log<phosphor::logging::level::ERR>(
248 "Error getting managed objects from connection",
249 phosphor::logging::entry("CONNECTION=%s",
250 sensorConnection.c_str()));
251 return false;
252 }
253
254 SensorCache[sensorConnection] = managedObjects;
255 }
256 auto connection = SensorCache.find(sensorConnection);
257 if (connection == SensorCache.end())
258 {
259 return false;
260 }
261 auto path = connection->second.find(sensorPath);
262 if (path == connection->second.end())
263 {
264 return false;
265 }
266 sensorMap = path->second;
267
268 return true;
269}
270
271/* sensor commands */
272ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
273 ipmi_request_t request,
274 ipmi_response_t response,
275 ipmi_data_len_t dataLen,
276 ipmi_context_t context)
277{
278 *dataLen = 0;
279 printCommand(+netfn, +cmd);
280 return IPMI_CC_INVALID;
281}
282
James Feist7aaf3fe2019-06-25 11:52:11 -0700283namespace meHealth
284{
285constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
286constexpr const char *path = "/xyz/openbmc_project/status/me";
287constexpr const char *interface = "xyz.openbmc_project.SetHealth";
288constexpr const char *method = "SetHealth";
289constexpr const char *critical = "critical";
290constexpr const char *warning = "warning";
291constexpr const char *ok = "ok";
292} // namespace meHealth
293
294static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
295{
296 constexpr const std::array<uint8_t, 10> critical = {
297 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
298 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
299 0x1A};
300
301 std::string state;
302 if (std::find(critical.begin(), critical.end(), eventData2) !=
303 critical.end())
304 {
305 state = meHealth::critical;
306 }
307 // special case 0x3 as we only care about a few states
308 else if (eventData2 == 0x3)
309 {
310 if (eventData3 <= 0x2)
311 {
312 state = meHealth::warning;
313 }
314 else
315 {
316 return;
317 }
318 }
319 else if (std::find(warning.begin(), warning.end(), eventData2) !=
320 warning.end())
321 {
322 state = meHealth::warning;
323 }
324 else
325 {
326 return;
327 }
328 if (disable)
329 {
330 state = meHealth::ok;
331 }
332
333 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
334 auto setHealth =
335 dbus->new_method_call(meHealth::busname, meHealth::path,
336 meHealth::interface, meHealth::method);
337 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
338 try
339 {
340 dbus->call(setHealth);
341 }
342 catch (sdbusplus::exception_t &)
343 {
344 phosphor::logging::log<phosphor::logging::level::ERR>(
345 "Failed to set ME Health");
346 }
347}
348
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700349ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
350{
James Feist7aaf3fe2019-06-25 11:52:11 -0700351 constexpr const uint8_t meId = 0x2C;
352 constexpr const uint8_t meSensorNum = 0x17;
353 constexpr const uint8_t disabled = 0x80;
354
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700355 uint8_t generatorID = 0;
356 uint8_t evmRev = 0;
357 uint8_t sensorType = 0;
358 uint8_t sensorNum = 0;
359 uint8_t eventType = 0;
360 uint8_t eventData1 = 0;
361 std::optional<uint8_t> eventData2 = 0;
362 std::optional<uint8_t> eventData3 = 0;
363
364 // todo: This check is supposed to be based on the incoming channel.
365 // e.g. system channel will provide upto 8 bytes including generator
366 // ID, but ipmb channel will provide only up to 7 bytes without the
367 // generator ID.
368 // Support for this check is coming in future patches, so for now just base
369 // it on if the first byte is the EvMRev (0x04).
370 if (p.size() && p.data()[0] == 0x04)
371 {
372 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
373 eventData2, eventData3);
374 // todo: the generator ID for this channel is supposed to come from the
375 // IPMB requesters slave address. Support for this is coming in future
376 // patches, so for now just assume it is coming from the ME (0x2C).
377 generatorID = 0x2C;
378 }
379 else
380 {
381 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
382 eventData1, eventData2, eventData3);
383 }
384 if (!p.fullyUnpacked())
385 {
386 return ipmi::responseReqDataLenInvalid();
387 }
388
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700389 // Send this request to the Redfish hooks to log it as a Redfish message
390 // instead. There is no need to add it to the SEL, so just return success.
391 intel_oem::ipmi::sel::checkRedfishHooks(
392 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
393 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700394
James Feist7aaf3fe2019-06-25 11:52:11 -0700395 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
396 eventData3)
397 {
398 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
399 }
400
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700401 return ipmi::responseSuccess();
402}
403
James Feist0cd014a2019-04-08 15:04:33 -0700404ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
405 ipmiSenGetSensorReading(uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700406{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700407 std::string connection;
408 std::string path;
409
410 auto status = getSensorConnection(sensnum, connection, path);
411 if (status)
412 {
James Feist0cd014a2019-04-08 15:04:33 -0700413 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700414 }
415
416 SensorMap sensorMap;
417 if (!getSensorMap(connection, path, sensorMap))
418 {
James Feist0cd014a2019-04-08 15:04:33 -0700419 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700420 }
421 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
422
423 if (sensorObject == sensorMap.end() ||
424 sensorObject->second.find("Value") == sensorObject->second.end())
425 {
James Feist0cd014a2019-04-08 15:04:33 -0700426 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700427 }
James Feist0cd014a2019-04-08 15:04:33 -0700428 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700429 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700430
Yong Li1f2eb5e2019-05-23 14:07:17 +0800431 double max = 0;
432 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700433 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700434
435 int16_t mValue = 0;
436 int16_t bValue = 0;
437 int8_t rExp = 0;
438 int8_t bExp = 0;
439 bool bSigned = false;
440
441 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
442 {
James Feist0cd014a2019-04-08 15:04:33 -0700443 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700444 }
445
James Feist0cd014a2019-04-08 15:04:33 -0700446 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700447 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700448 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700449 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700450 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800451 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700452
James Feist0cd014a2019-04-08 15:04:33 -0700453 uint8_t thresholds = 0;
454
455 auto warningObject =
456 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
457 if (warningObject != sensorMap.end())
458 {
459 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
460 auto alarmLow = warningObject->second.find("WarningAlarmLow");
461 if (alarmHigh != warningObject->second.end())
462 {
463 if (std::get<bool>(alarmHigh->second))
464 {
465 thresholds |= static_cast<uint8_t>(
466 IPMISensorReadingByte3::upperNonCritical);
467 }
468 }
469 if (alarmLow != warningObject->second.end())
470 {
471 if (std::get<bool>(alarmLow->second))
472 {
473 thresholds |= static_cast<uint8_t>(
474 IPMISensorReadingByte3::lowerNonCritical);
475 }
476 }
477 }
478
479 auto criticalObject =
480 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
481 if (criticalObject != sensorMap.end())
482 {
483 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
484 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
485 if (alarmHigh != criticalObject->second.end())
486 {
487 if (std::get<bool>(alarmHigh->second))
488 {
489 thresholds |=
490 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
491 }
492 }
493 if (alarmLow != criticalObject->second.end())
494 {
495 if (std::get<bool>(alarmLow->second))
496 {
497 thresholds |=
498 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
499 }
500 }
501 }
502
503 // no discrete as of today so optional byte is never returned
504 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700505}
506
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000507/** @brief implements the Set Sensor threshold command
508 * @param sensorNumber - sensor number
509 * @param lowerNonCriticalThreshMask
510 * @param lowerCriticalThreshMask
511 * @param lowerNonRecovThreshMask
512 * @param upperNonCriticalThreshMask
513 * @param upperCriticalThreshMask
514 * @param upperNonRecovThreshMask
515 * @param reserved
516 * @param lowerNonCritical - lower non-critical threshold
517 * @param lowerCritical - Lower critical threshold
518 * @param lowerNonRecoverable - Lower non recovarable threshold
519 * @param upperNonCritical - Upper non-critical threshold
520 * @param upperCritical - Upper critical
521 * @param upperNonRecoverable - Upper Non-recoverable
522 *
523 * @returns IPMI completion code
524 */
525ipmi::RspType<> ipmiSenSetSensorThresholds(
526 uint8_t sensorNum, bool lowerNonCriticalThreshMask,
527 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
528 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
529 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
530 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
531 uint8_t upperNonCritical, uint8_t upperCritical,
532 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700533{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000534 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700535
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000536 if (reserved)
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
541 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000542 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700543 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000544 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700545 }
546
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000547 // if none of the threshold mask are set, nothing to do
548 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
549 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
550 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700551 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000552 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700553 }
554
555 std::string connection;
556 std::string path;
557
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000558 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700559 if (status)
560 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000561 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700562 }
563 SensorMap sensorMap;
564 if (!getSensorMap(connection, path, sensorMap))
565 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000566 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700567 }
568
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700569 double max = 0;
570 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700571 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700572
573 int16_t mValue = 0;
574 int16_t bValue = 0;
575 int8_t rExp = 0;
576 int8_t bExp = 0;
577 bool bSigned = false;
578
579 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
580 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000581 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700582 }
583
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700584 // store a vector of property name, value to set, and interface
585 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
586
587 // define the indexes of the tuple
588 constexpr uint8_t propertyName = 0;
589 constexpr uint8_t thresholdValue = 1;
590 constexpr uint8_t interface = 2;
591 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000592 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700593 {
594 auto findThreshold =
595 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
596 if (findThreshold == sensorMap.end())
597 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000598 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700599 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000600 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700601 {
602 auto findLower = findThreshold->second.find("CriticalLow");
603 if (findLower == findThreshold->second.end())
604 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000605 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700606 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000607 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700608 findThreshold->first);
609 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000610 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700611 {
612 auto findUpper = findThreshold->second.find("CriticalHigh");
613 if (findUpper == findThreshold->second.end())
614 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000615 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700616 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000617 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700618 findThreshold->first);
619 }
620 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000621 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700622 {
623 auto findThreshold =
624 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
625 if (findThreshold == sensorMap.end())
626 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000629 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700630 {
631 auto findLower = findThreshold->second.find("WarningLow");
632 if (findLower == findThreshold->second.end())
633 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000634 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700635 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000636 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700637 findThreshold->first);
638 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000639 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700640 {
641 auto findUpper = findThreshold->second.find("WarningHigh");
642 if (findUpper == findThreshold->second.end())
643 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000644 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700645 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000646 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700647 findThreshold->first);
648 }
649 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650 for (const auto &property : thresholdsToSet)
651 {
652 // from section 36.3 in the IPMI Spec, assume all linear
653 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800654 (bValue * std::pow(10.0, bExp))) *
655 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700656 setDbusProperty(
657 *getSdBus(), connection, path, std::get<interface>(property),
658 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700659 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000660 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700661}
662
James Feist902c4c52019-04-16 14:51:31 -0700663IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700664{
James Feist902c4c52019-04-16 14:51:31 -0700665 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700666 auto warningInterface =
667 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
668 auto criticalInterface =
669 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
670
671 if ((warningInterface != sensorMap.end()) ||
672 (criticalInterface != sensorMap.end()))
673 {
674 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
675
676 if (sensorPair == sensorMap.end())
677 {
678 // should not have been able to find a sensor not implementing
679 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700680 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700681 }
682
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800683 double max = 0;
684 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700685 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700686
687 int16_t mValue = 0;
688 int16_t bValue = 0;
689 int8_t rExp = 0;
690 int8_t bExp = 0;
691 bool bSigned = false;
692
693 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
694 {
James Feist902c4c52019-04-16 14:51:31 -0700695 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700696 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700697 if (warningInterface != sensorMap.end())
698 {
699 auto &warningMap = warningInterface->second;
700
701 auto warningHigh = warningMap.find("WarningHigh");
702 auto warningLow = warningMap.find("WarningLow");
703
704 if (warningHigh != warningMap.end())
705 {
James Feist902c4c52019-04-16 14:51:31 -0700706
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700707 double value =
708 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700709 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700710 value, mValue, rExp, bValue, bExp, bSigned);
711 }
712 if (warningLow != warningMap.end())
713 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700714 double value =
715 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700716 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700717 value, mValue, rExp, bValue, bExp, bSigned);
718 }
719 }
720 if (criticalInterface != sensorMap.end())
721 {
722 auto &criticalMap = criticalInterface->second;
723
724 auto criticalHigh = criticalMap.find("CriticalHigh");
725 auto criticalLow = criticalMap.find("CriticalLow");
726
727 if (criticalHigh != criticalMap.end())
728 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700729 double value =
730 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700731 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700732 value, mValue, rExp, bValue, bExp, bSigned);
733 }
734 if (criticalLow != criticalMap.end())
735 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700736 double value =
737 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700738 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700739 value, mValue, rExp, bValue, bExp, bSigned);
740 }
741 }
742 }
James Feist902c4c52019-04-16 14:51:31 -0700743 return resp;
744}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700745
James Feist902c4c52019-04-16 14:51:31 -0700746ipmi::RspType<uint8_t, // readable
747 uint8_t, // lowerNCrit
748 uint8_t, // lowerCrit
749 uint8_t, // lowerNrecoverable
750 uint8_t, // upperNC
751 uint8_t, // upperCrit
752 uint8_t> // upperNRecoverable
753 ipmiSenGetSensorThresholds(uint8_t sensorNumber)
754{
755 std::string connection;
756 std::string path;
757
758 auto status = getSensorConnection(sensorNumber, connection, path);
759 if (status)
760 {
761 return ipmi::response(status);
762 }
763
764 SensorMap sensorMap;
765 if (!getSensorMap(connection, path, sensorMap))
766 {
767 return ipmi::responseResponseError();
768 }
769
770 IPMIThresholds thresholdData;
771 try
772 {
773 thresholdData = getIPMIThresholds(sensorMap);
774 }
775 catch (std::exception &)
776 {
777 return ipmi::responseResponseError();
778 }
779
780 uint8_t readable = 0;
781 uint8_t lowerNC = 0;
782 uint8_t lowerCritical = 0;
783 uint8_t lowerNonRecoverable = 0;
784 uint8_t upperNC = 0;
785 uint8_t upperCritical = 0;
786 uint8_t upperNonRecoverable = 0;
787
788 if (thresholdData.warningHigh)
789 {
790 readable |=
791 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
792 upperNC = *thresholdData.warningHigh;
793 }
794 if (thresholdData.warningLow)
795 {
796 readable |=
797 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
798 lowerNC = *thresholdData.warningLow;
799 }
800
801 if (thresholdData.criticalHigh)
802 {
803 readable |=
804 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
805 upperCritical = *thresholdData.criticalHigh;
806 }
807 if (thresholdData.criticalLow)
808 {
809 readable |=
810 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
811 lowerCritical = *thresholdData.criticalLow;
812 }
813
814 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
815 lowerNonRecoverable, upperNC, upperCritical,
816 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700817}
818
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000819/** @brief implements the get Sensor event enable command
820 * @param sensorNumber - sensor number
821 *
822 * @returns IPMI completion code plus response data
823 * - enabled - Sensor Event messages
824 * - assertionEnabledLsb - Assertion event messages
825 * - assertionEnabledMsb - Assertion event messages
826 * - deassertionEnabledLsb - Deassertion event messages
827 * - deassertionEnabledMsb - Deassertion event messages
828 */
829
830ipmi::RspType<uint8_t, // enabled
831 uint8_t, // assertionEnabledLsb
832 uint8_t, // assertionEnabledMsb
833 uint8_t, // deassertionEnabledLsb
834 uint8_t> // deassertionEnabledMsb
835 ipmiSenGetSensorEventEnable(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700836{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700837 std::string connection;
838 std::string path;
839
Patrick Venturea41714c2019-09-25 16:59:41 -0700840 uint8_t enabled = 0;
841 uint8_t assertionEnabledLsb = 0;
842 uint8_t assertionEnabledMsb = 0;
843 uint8_t deassertionEnabledLsb = 0;
844 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000845
846 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700847 if (status)
848 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000849 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700850 }
851
852 SensorMap sensorMap;
853 if (!getSensorMap(connection, path, sensorMap))
854 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000855 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700856 }
857
858 auto warningInterface =
859 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
860 auto criticalInterface =
861 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700862 if ((warningInterface != sensorMap.end()) ||
863 (criticalInterface != sensorMap.end()))
864 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000865 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700866 IPMISensorEventEnableByte2::sensorScanningEnable);
867 if (warningInterface != sensorMap.end())
868 {
869 auto &warningMap = warningInterface->second;
870
871 auto warningHigh = warningMap.find("WarningHigh");
872 auto warningLow = warningMap.find("WarningLow");
873 if (warningHigh != warningMap.end())
874 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000875 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700876 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000877 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700878 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
879 }
880 if (warningLow != warningMap.end())
881 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000882 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700883 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000884 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700885 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
886 }
887 }
888 if (criticalInterface != sensorMap.end())
889 {
890 auto &criticalMap = criticalInterface->second;
891
892 auto criticalHigh = criticalMap.find("CriticalHigh");
893 auto criticalLow = criticalMap.find("CriticalLow");
894
895 if (criticalHigh != criticalMap.end())
896 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000897 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700898 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000899 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700900 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
901 }
902 if (criticalLow != criticalMap.end())
903 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000904 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700905 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000906 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700907 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
908 }
909 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700910 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000911
912 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
913 assertionEnabledMsb, deassertionEnabledLsb,
914 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700915}
916
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000917/** @brief implements the get Sensor event status command
918 * @param sensorNumber - sensor number, FFh = reserved
919 *
920 * @returns IPMI completion code plus response data
921 * - sensorEventStatus - Sensor Event messages state
922 * - assertions - Assertion event messages
923 * - deassertions - Deassertion event messages
924 */
925ipmi::RspType<uint8_t, // sensorEventStatus
926 std::bitset<16>, // assertions
927 std::bitset<16> // deassertion
928 >
929 ipmiSenGetSensorEventStatus(uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700930{
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000931 if (sensorNum == 0xFF)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700932 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000933 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700934 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700935
936 std::string connection;
937 std::string path;
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000938 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700939 if (status)
940 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000941 phosphor::logging::log<phosphor::logging::level::ERR>(
942 "ipmiSenGetSensorEventStatus: Sensor connection Error",
943 phosphor::logging::entry("SENSOR=%d", sensorNum));
944 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700945 }
946
947 SensorMap sensorMap;
948 if (!getSensorMap(connection, path, sensorMap))
949 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000950 phosphor::logging::log<phosphor::logging::level::ERR>(
951 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
952 phosphor::logging::entry("SENSOR=%s", path.c_str()));
953 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700954 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700955 auto warningInterface =
956 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
957 auto criticalInterface =
958 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
959
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000960 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700961 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
962
James Feist392786a2019-03-19 13:36:10 -0700963 std::optional<bool> criticalDeassertHigh =
964 thresholdDeassertMap[path]["CriticalAlarmHigh"];
965 std::optional<bool> criticalDeassertLow =
966 thresholdDeassertMap[path]["CriticalAlarmLow"];
967 std::optional<bool> warningDeassertHigh =
968 thresholdDeassertMap[path]["WarningAlarmHigh"];
969 std::optional<bool> warningDeassertLow =
970 thresholdDeassertMap[path]["WarningAlarmLow"];
971
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000972 std::bitset<16> assertions = 0;
973 std::bitset<16> deassertions = 0;
974
James Feist392786a2019-03-19 13:36:10 -0700975 if (criticalDeassertHigh && !*criticalDeassertHigh)
976 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000977 deassertions.set(static_cast<size_t>(
978 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700979 }
980 if (criticalDeassertLow && !*criticalDeassertLow)
981 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000982 deassertions.set(static_cast<size_t>(
983 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -0700984 }
985 if (warningDeassertHigh && !*warningDeassertHigh)
986 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000987 deassertions.set(static_cast<size_t>(
988 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700989 }
990 if (warningDeassertLow && !*warningDeassertLow)
991 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000992 deassertions.set(static_cast<size_t>(
993 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700994 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700995 if ((warningInterface != sensorMap.end()) ||
996 (criticalInterface != sensorMap.end()))
997 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000998 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700999 IPMISensorEventEnableByte2::eventMessagesEnable);
1000 if (warningInterface != sensorMap.end())
1001 {
1002 auto &warningMap = warningInterface->second;
1003
1004 auto warningHigh = warningMap.find("WarningAlarmHigh");
1005 auto warningLow = warningMap.find("WarningAlarmLow");
1006 auto warningHighAlarm = false;
1007 auto warningLowAlarm = false;
1008
1009 if (warningHigh != warningMap.end())
1010 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001011 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001012 }
1013 if (warningLow != warningMap.end())
1014 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001015 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001016 }
1017 if (warningHighAlarm)
1018 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001019 assertions.set(
1020 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1021 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001022 }
1023 if (warningLowAlarm)
1024 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001025 assertions.set(
1026 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1027 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001028 }
1029 }
1030 if (criticalInterface != sensorMap.end())
1031 {
1032 auto &criticalMap = criticalInterface->second;
1033
1034 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1035 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1036 auto criticalHighAlarm = false;
1037 auto criticalLowAlarm = false;
1038
1039 if (criticalHigh != criticalMap.end())
1040 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001041 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001042 }
1043 if (criticalLow != criticalMap.end())
1044 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001045 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001046 }
1047 if (criticalHighAlarm)
1048 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001049 assertions.set(
1050 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1051 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001052 }
1053 if (criticalLowAlarm)
1054 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001055 assertions.set(static_cast<size_t>(
1056 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001057 }
1058 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001059 }
1060
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001061 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001062}
1063
1064/* end sensor commands */
1065
1066/* storage commands */
1067
James Feist74c50c62019-08-14 14:18:41 -07001068ipmi::RspType<uint8_t, // sdr version
1069 uint16_t, // record count
1070 uint16_t, // free space
1071 uint32_t, // most recent addition
1072 uint32_t, // most recent erase
1073 uint8_t // operationSupport
1074 >
1075 ipmiStorageGetSDRRepositoryInfo(void)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001076{
James Feist74c50c62019-08-14 14:18:41 -07001077 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001078 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1079 {
James Feist74c50c62019-08-14 14:18:41 -07001080 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001081 }
1082
James Feist74c50c62019-08-14 14:18:41 -07001083 size_t fruCount = 0;
1084 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1085 if (ret != ipmi::ccSuccess)
1086 {
1087 return ipmi::response(ret);
1088 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089
James Feist74c50c62019-08-14 14:18:41 -07001090 uint16_t recordCount =
1091 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001092
James Feist74c50c62019-08-14 14:18:41 -07001093 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001094 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001095
1096 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001097 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001098 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001099 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001100 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1101 unspecifiedFreeSpace, sdrLastAdd,
1102 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001103}
1104
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001105/** @brief implements the get SDR allocation info command
1106 *
1107 * @returns IPMI completion code plus response data
1108 * - allocUnits - Number of possible allocation units
1109 * - allocUnitSize - Allocation unit size in bytes.
1110 * - allocUnitFree - Number of free allocation units
1111 * - allocUnitLargestFree - Largest free block in allocation units
1112 * - maxRecordSize - Maximum record size in allocation units.
1113 */
1114ipmi::RspType<uint16_t, // allocUnits
1115 uint16_t, // allocUnitSize
1116 uint16_t, // allocUnitFree
1117 uint16_t, // allocUnitLargestFree
1118 uint8_t // maxRecordSize
1119 >
1120 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001121{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001122 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001123 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001124
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001125 constexpr uint16_t allocUnitFree = 0;
1126 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001127 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001128 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001129
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001130 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1131 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001132}
1133
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001134/** @brief implements the reserve SDR command
1135 * @returns IPMI completion code plus response data
1136 * - sdrReservationID
1137 */
1138ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001139{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001140 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001141 if (sdrReservationID == 0)
1142 {
1143 sdrReservationID++;
1144 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001145
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001146 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001147}
1148
James Feistb49a98a2019-04-16 13:48:09 -07001149ipmi::RspType<uint16_t, // next record ID
1150 std::vector<uint8_t> // payload
1151 >
1152 ipmiStorageGetSDR(uint16_t reservationID, uint16_t recordID, uint8_t offset,
1153 uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001154{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001155 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001156
1157 // reservation required for partial reads with non zero offset into
1158 // record
James Feistb49a98a2019-04-16 13:48:09 -07001159 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001160 {
James Feistb49a98a2019-04-16 13:48:09 -07001161 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001162 }
1163
1164 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1165 {
James Feistb49a98a2019-04-16 13:48:09 -07001166 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167 }
1168
1169 size_t fruCount = 0;
James Feist74c50c62019-08-14 14:18:41 -07001170 ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
1171 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001172 {
James Feistb49a98a2019-04-16 13:48:09 -07001173 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001174 }
1175
James Feist74c50c62019-08-14 14:18:41 -07001176 size_t lastRecord =
1177 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001178 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001179 {
James Feistb49a98a2019-04-16 13:48:09 -07001180 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001181 }
James Feistb49a98a2019-04-16 13:48:09 -07001182 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001183 {
James Feistb49a98a2019-04-16 13:48:09 -07001184 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001185 }
1186
James Feistb49a98a2019-04-16 13:48:09 -07001187 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001188
James Feistb49a98a2019-04-16 13:48:09 -07001189 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001190 {
James Feist74c50c62019-08-14 14:18:41 -07001191 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001192 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001193 if (fruIndex >= fruCount)
1194 {
James Feist74c50c62019-08-14 14:18:41 -07001195 // handle type 12 hardcoded records
1196 size_t type12Index = fruIndex - fruCount;
1197 if (type12Index >= ipmi::storage::type12Count ||
1198 offset > sizeof(Type12Record))
1199 {
1200 return ipmi::responseInvalidFieldRequest();
1201 }
1202 std::vector<uint8_t> record =
1203 ipmi::storage::getType12SDRs(type12Index, recordID);
1204 if (record.size() < (offset + bytesToRead))
1205 {
1206 bytesToRead = record.size() - offset;
1207 }
James Feistb49a98a2019-04-16 13:48:09 -07001208
James Feist74c50c62019-08-14 14:18:41 -07001209 recordData.insert(recordData.end(), record.begin() + offset,
1210 record.begin() + offset + bytesToRead);
1211 }
1212 else
1213 {
1214 // handle fru records
1215 get_sdr::SensorDataFruRecord data;
1216 if (offset > sizeof(data))
1217 {
1218 return ipmi::responseInvalidFieldRequest();
1219 }
1220 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1221 if (ret != IPMI_CC_OK)
1222 {
1223 return ipmi::response(ret);
1224 }
1225 data.header.record_id_msb = recordID << 8;
1226 data.header.record_id_lsb = recordID & 0xFF;
1227 if (sizeof(data) < (offset + bytesToRead))
1228 {
1229 bytesToRead = sizeof(data) - offset;
1230 }
1231
1232 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1233 recordData.insert(recordData.end(), respStart,
1234 respStart + bytesToRead);
1235 }
James Feistb49a98a2019-04-16 13:48:09 -07001236
1237 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001238 }
1239
1240 std::string connection;
1241 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001242 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001243 for (const auto &sensor : sensorTree)
1244 {
1245 if (sensorIndex-- == 0)
1246 {
1247 if (!sensor.second.size())
1248 {
James Feistb49a98a2019-04-16 13:48:09 -07001249 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001250 }
1251 connection = sensor.second.begin()->first;
1252 path = sensor.first;
1253 break;
1254 }
1255 }
1256
1257 SensorMap sensorMap;
1258 if (!getSensorMap(connection, path, sensorMap))
1259 {
James Feistb49a98a2019-04-16 13:48:09 -07001260 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001261 }
James Feistb49a98a2019-04-16 13:48:09 -07001262 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001263 get_sdr::SensorDataFullRecord record = {0};
1264
James Feistb49a98a2019-04-16 13:48:09 -07001265 record.header.record_id_msb = recordID << 8;
1266 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001267 record.header.sdr_version = ipmiSdrVersion;
1268 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1269 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1270 sizeof(get_sdr::SensorDataRecordHeader);
1271 record.key.owner_id = 0x20;
1272 record.key.owner_lun = 0x0;
1273 record.key.sensor_number = sensornumber;
1274
James Feist7086a882019-03-13 10:46:00 -07001275 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001276 record.body.sensor_type = getSensorTypeFromPath(path);
1277 std::string type = getSensorTypeStringFromPath(path);
1278 auto typeCstr = type.c_str();
1279 auto findUnits = sensorUnits.find(typeCstr);
1280 if (findUnits != sensorUnits.end())
1281 {
1282 record.body.sensor_units_2_base =
1283 static_cast<uint8_t>(findUnits->second);
1284 } // else default 0x0 unspecified
1285
1286 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1287
1288 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1289 if (sensorObject == sensorMap.end())
1290 {
James Feistb49a98a2019-04-16 13:48:09 -07001291 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001292 }
1293
Patrick Venture262276f2019-10-18 13:27:59 -07001294 uint8_t entityId = 0;
1295 uint8_t entityInstance = 0x01;
1296
1297 // follow the association chain to get the parent board's entityid and
1298 // entityInstance
1299 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1300
1301 record.body.entity_id = entityId;
1302 record.body.entity_instance = entityInstance;
1303
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001304 auto maxObject = sensorObject->second.find("MaxValue");
1305 auto minObject = sensorObject->second.find("MinValue");
Josh Lehanca9dcbd2019-11-18 15:59:59 -08001306
1307 // If min and/or max are left unpopulated,
1308 // then default to what a signed byte would be, namely (-128,127) range.
1309 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1310 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001311 if (maxObject != sensorObject->second.end())
1312 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001313 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001314 }
1315
1316 if (minObject != sensorObject->second.end())
1317 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001318 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001319 }
1320
Yong Li1f2eb5e2019-05-23 14:07:17 +08001321 int16_t mValue = 0;
1322 int8_t rExp = 0;
1323 int16_t bValue = 0;
1324 int8_t bExp = 0;
1325 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001326
1327 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1328 {
James Feistb49a98a2019-04-16 13:48:09 -07001329 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001330 }
1331
Josh Lehan7cc9e472019-11-18 16:09:26 -08001332 // The record.body is a struct SensorDataFullRecordBody
1333 // from sensorhandler.hpp in phosphor-ipmi-host.
1334 // The meaning of these bits appears to come from
1335 // table 43.1 of the IPMI spec.
1336 // The above 5 sensor attributes are stuffed in as follows:
1337 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1338 // Byte 22-24 are for other purposes
1339 // Byte 25 = MMMMMMMM = LSB of M
1340 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1341 // Byte 27 = BBBBBBBB = LSB of B
1342 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1343 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1344 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1345
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001346 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1347 record.body.m_lsb = mValue & 0xFF;
1348
Josh Lehan7cc9e472019-11-18 16:09:26 -08001349 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1350 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1351
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001352 // move the smallest bit of the MSB into place (bit 9)
1353 // the MSbs are bits 7:8 in m_msb_and_tolerance
Josh Lehan7cc9e472019-11-18 16:09:26 -08001354 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001355
1356 record.body.b_lsb = bValue & 0xFF;
1357
Josh Lehan7cc9e472019-11-18 16:09:26 -08001358 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1359 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1360
1361 // move the smallest bit of the MSB into place (bit 9)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001362 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
Josh Lehan7cc9e472019-11-18 16:09:26 -08001363 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001364
Josh Lehan7cc9e472019-11-18 16:09:26 -08001365 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1366 uint8_t rExpBits = rExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001367
Josh Lehan7cc9e472019-11-18 16:09:26 -08001368 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1369 uint8_t bExpBits = bExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001370
Josh Lehan7cc9e472019-11-18 16:09:26 -08001371 // move rExp and bExp into place
1372 record.body.r_b_exponents =
1373 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1374
1375 // Set the analog reading byte interpretation accordingly
1376 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1377
1378 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1379 // These seem redundant, but derivable from the above 5 attributes
1380 // Original comment said "todo fill out rest of units"
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001381
1382 // populate sensor name from path
1383 std::string name;
1384 size_t nameStart = path.rfind("/");
1385 if (nameStart != std::string::npos)
1386 {
1387 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1388 }
1389
1390 std::replace(name.begin(), name.end(), '_', ' ');
1391 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1392 {
James Feist979a2322019-05-15 09:06:54 -07001393 // try to not truncate by replacing common words
1394 constexpr std::array<std::pair<const char *, const char *>, 2>
1395 replaceWords = {std::make_pair("Output", "Out"),
1396 std::make_pair("Input", "In")};
1397 for (const auto &[find, replace] : replaceWords)
1398 {
1399 boost::replace_all(name, find, replace);
1400 }
1401
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001402 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1403 }
1404 record.body.id_string_info = name.size();
1405 std::strncpy(record.body.id_string, name.c_str(),
1406 sizeof(record.body.id_string));
1407
James Feistc4b15bc2019-04-16 15:41:39 -07001408 IPMIThresholds thresholdData;
1409 try
1410 {
1411 thresholdData = getIPMIThresholds(sensorMap);
1412 }
1413 catch (std::exception &)
1414 {
1415 return ipmi::responseResponseError();
1416 }
1417
1418 if (thresholdData.criticalHigh)
1419 {
1420 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1421 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1422 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1423 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1424 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1425 record.body.discrete_reading_setting_mask[0] |=
1426 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1427 }
1428 if (thresholdData.warningHigh)
1429 {
1430 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1431 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1432 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1433 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1434 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1435 record.body.discrete_reading_setting_mask[0] |=
1436 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1437 }
1438 if (thresholdData.criticalLow)
1439 {
1440 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1441 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1442 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1443 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1444 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1445 record.body.discrete_reading_setting_mask[0] |=
1446 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1447 }
1448 if (thresholdData.warningLow)
1449 {
1450 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1451 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1452 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1453 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1454 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1455 record.body.discrete_reading_setting_mask[0] |=
1456 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1457 }
1458
1459 // everything that is readable is setable
1460 record.body.discrete_reading_setting_mask[1] =
1461 record.body.discrete_reading_setting_mask[0];
1462
James Feistb49a98a2019-04-16 13:48:09 -07001463 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001464 {
James Feistb49a98a2019-04-16 13:48:09 -07001465 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001466 }
1467
James Feistb49a98a2019-04-16 13:48:09 -07001468 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1469 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001470
James Feistb49a98a2019-04-16 13:48:09 -07001471 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001472}
1473/* end storage commands */
1474
1475void registerSensorFunctions()
1476{
1477 // get firmware version information
1478 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1479 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1480
1481 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001482 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1483 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001484
1485 // <Set Sensor Reading and Event Status>
1486 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001487 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001488 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1489
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001490 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001491 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1492 ipmi::sensor_event::cmdPlatformEvent,
1493 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001494
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001495 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001496 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1497 ipmi::sensor_event::cmdGetSensorReading,
1498 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001499
1500 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001501 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1502 ipmi::sensor_event::cmdGetSensorThreshold,
1503 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001504
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001505 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001506 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1507 ipmi::sensor_event::cmdSetSensorThreshold,
1508 ipmi::Privilege::Operator,
1509 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001510
1511 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001512 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1513 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001514 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001515
1516 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001517 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1518 ipmi::sensor_event::cmdGetSensorEventStatus,
1519 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001520
1521 // register all storage commands for both Sensor and Storage command
1522 // versions
1523
1524 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001525 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1526 ipmi::storage::cmdGetSdrRepositoryInfo,
1527 ipmi::Privilege::User,
1528 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001529
1530 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001531 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1532 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1533 ipmi::Privilege::User,
1534 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001535
1536 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001537 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1538 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001539 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001540
Vernon Mauery98bbf692019-09-16 11:14:59 -07001541 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1542 ipmi::storage::cmdReserveSdrRepository,
1543 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001544
1545 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001546 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1547 ipmi::sensor_event::cmdGetDeviceSdr,
1548 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001549
Vernon Mauery98bbf692019-09-16 11:14:59 -07001550 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1551 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1552 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001553}
1554} // namespace ipmi