blob: d500a008c985a52bf5b0dad120a67d040dde4457 [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
James Feist25690252019-12-23 12:25:49 -080051static constexpr int sensorMapUpdatePeriod = 10;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070052
53constexpr size_t maxSDRTotalSize =
54 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
55constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
56
57static uint16_t sdrReservationID;
58static uint32_t sdrLastAdd = noTimestamp;
59static uint32_t sdrLastRemove = noTimestamp;
60
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053061SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070062static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
63
Jason M. Bills17add592018-11-12 14:30:12 -080064// Specify the comparison required to sort and find char* map objects
65struct CmpStr
66{
67 bool operator()(const char *a, const char *b) const
68 {
69 return std::strcmp(a, b) < 0;
70 }
71};
72const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
73 sensorUnits{{{"temperature", SensorUnits::degreesC},
74 {"voltage", SensorUnits::volts},
75 {"current", SensorUnits::amps},
76 {"fan_tach", SensorUnits::rpm},
77 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070078
79void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070080
81static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070082 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070083 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
84 "sensors/'",
85 [](sdbusplus::message::message &m) {
86 sensorTree.clear();
87 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
88 std::chrono::system_clock::now().time_since_epoch())
89 .count();
90 });
91
92static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070093 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070094 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
95 "sensors/'",
96 [](sdbusplus::message::message &m) {
97 sensorTree.clear();
98 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
99 std::chrono::system_clock::now().time_since_epoch())
100 .count();
101 });
102
James Feist392786a2019-03-19 13:36:10 -0700103// this keeps track of deassertions for sensor event status command. A
104// deasertion can only happen if an assertion was seen first.
105static boost::container::flat_map<
106 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
107 thresholdDeassertMap;
108
109static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700110 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700111 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
112 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
113 [](sdbusplus::message::message &m) {
114 boost::container::flat_map<std::string, std::variant<bool, double>>
115 values;
116 m.read(std::string(), values);
117
118 auto findAssert =
119 std::find_if(values.begin(), values.end(), [](const auto &pair) {
120 return pair.first.find("Alarm") != std::string::npos;
121 });
122 if (findAssert != values.end())
123 {
124 auto ptr = std::get_if<bool>(&(findAssert->second));
125 if (ptr == nullptr)
126 {
127 phosphor::logging::log<phosphor::logging::level::ERR>(
128 "thresholdChanged: Assert non bool");
129 return;
130 }
131 if (*ptr)
132 {
133 phosphor::logging::log<phosphor::logging::level::INFO>(
134 "thresholdChanged: Assert",
135 phosphor::logging::entry("SENSOR=%s", m.get_path()));
136 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
137 }
138 else
139 {
140 auto &value =
141 thresholdDeassertMap[m.get_path()][findAssert->first];
142 if (value)
143 {
144 phosphor::logging::log<phosphor::logging::level::INFO>(
145 "thresholdChanged: deassert",
146 phosphor::logging::entry("SENSOR=%s", m.get_path()));
147 value = *ptr;
148 }
149 }
150 }
151 });
152
James Feistaecaef72019-04-26 10:30:32 -0700153static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
154 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700155{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700156 max = 127;
157 min = -128;
158
James Feistaecaef72019-04-26 10:30:32 -0700159 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
160 auto critical =
161 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
162 auto warning =
163 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
164
165 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700166 {
James Feistaecaef72019-04-26 10:30:32 -0700167 auto maxMap = sensorObject->second.find("MaxValue");
168 auto minMap = sensorObject->second.find("MinValue");
169
170 if (maxMap != sensorObject->second.end())
171 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700172 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700173 }
174 if (minMap != sensorObject->second.end())
175 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700176 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700177 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700178 }
James Feistaecaef72019-04-26 10:30:32 -0700179 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700180 {
James Feistaecaef72019-04-26 10:30:32 -0700181 auto lower = critical->second.find("CriticalLow");
182 auto upper = critical->second.find("CriticalHigh");
183 if (lower != critical->second.end())
184 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700185 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700186 min = std::min(value, min);
187 }
188 if (upper != critical->second.end())
189 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700190 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700191 max = std::max(value, max);
192 }
193 }
194 if (warning != sensorMap.end())
195 {
196
197 auto lower = warning->second.find("WarningLow");
198 auto upper = warning->second.find("WarningHigh");
199 if (lower != warning->second.end())
200 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700201 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700202 min = std::min(value, min);
203 }
204 if (upper != warning->second.end())
205 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700206 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700207 max = std::max(value, max);
208 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700209 }
210}
211
James Feist25690252019-12-23 12:25:49 -0800212static bool getSensorMap(boost::asio::yield_context yield,
213 std::string sensorConnection, std::string sensorPath,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700214 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();
James Feist25690252019-12-23 12:25:49 -0800235 boost::system::error_code ec;
236 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
237 yield, ec, sensorConnection.c_str(), "/",
238 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
239 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700240 {
241 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800242 "GetMangagedObjects for getSensorMap failed",
243 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
244
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700245 return false;
246 }
247
248 SensorCache[sensorConnection] = managedObjects;
249 }
250 auto connection = SensorCache.find(sensorConnection);
251 if (connection == SensorCache.end())
252 {
253 return false;
254 }
255 auto path = connection->second.find(sensorPath);
256 if (path == connection->second.end())
257 {
258 return false;
259 }
260 sensorMap = path->second;
261
262 return true;
263}
264
265/* sensor commands */
266ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
267 ipmi_request_t request,
268 ipmi_response_t response,
269 ipmi_data_len_t dataLen,
270 ipmi_context_t context)
271{
272 *dataLen = 0;
273 printCommand(+netfn, +cmd);
274 return IPMI_CC_INVALID;
275}
276
James Feist7aaf3fe2019-06-25 11:52:11 -0700277namespace meHealth
278{
279constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
280constexpr const char *path = "/xyz/openbmc_project/status/me";
281constexpr const char *interface = "xyz.openbmc_project.SetHealth";
282constexpr const char *method = "SetHealth";
283constexpr const char *critical = "critical";
284constexpr const char *warning = "warning";
285constexpr const char *ok = "ok";
286} // namespace meHealth
287
288static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
289{
290 constexpr const std::array<uint8_t, 10> critical = {
291 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
292 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
293 0x1A};
294
295 std::string state;
296 if (std::find(critical.begin(), critical.end(), eventData2) !=
297 critical.end())
298 {
299 state = meHealth::critical;
300 }
301 // special case 0x3 as we only care about a few states
302 else if (eventData2 == 0x3)
303 {
304 if (eventData3 <= 0x2)
305 {
306 state = meHealth::warning;
307 }
308 else
309 {
310 return;
311 }
312 }
313 else if (std::find(warning.begin(), warning.end(), eventData2) !=
314 warning.end())
315 {
316 state = meHealth::warning;
317 }
318 else
319 {
320 return;
321 }
322 if (disable)
323 {
324 state = meHealth::ok;
325 }
326
327 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
328 auto setHealth =
329 dbus->new_method_call(meHealth::busname, meHealth::path,
330 meHealth::interface, meHealth::method);
331 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
332 try
333 {
334 dbus->call(setHealth);
335 }
336 catch (sdbusplus::exception_t &)
337 {
338 phosphor::logging::log<phosphor::logging::level::ERR>(
339 "Failed to set ME Health");
340 }
341}
342
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700343ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
344{
James Feist7aaf3fe2019-06-25 11:52:11 -0700345 constexpr const uint8_t meId = 0x2C;
346 constexpr const uint8_t meSensorNum = 0x17;
347 constexpr const uint8_t disabled = 0x80;
348
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700349 uint8_t generatorID = 0;
350 uint8_t evmRev = 0;
351 uint8_t sensorType = 0;
352 uint8_t sensorNum = 0;
353 uint8_t eventType = 0;
354 uint8_t eventData1 = 0;
355 std::optional<uint8_t> eventData2 = 0;
356 std::optional<uint8_t> eventData3 = 0;
357
358 // todo: This check is supposed to be based on the incoming channel.
359 // e.g. system channel will provide upto 8 bytes including generator
360 // ID, but ipmb channel will provide only up to 7 bytes without the
361 // generator ID.
362 // Support for this check is coming in future patches, so for now just base
363 // it on if the first byte is the EvMRev (0x04).
364 if (p.size() && p.data()[0] == 0x04)
365 {
366 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
367 eventData2, eventData3);
368 // todo: the generator ID for this channel is supposed to come from the
369 // IPMB requesters slave address. Support for this is coming in future
370 // patches, so for now just assume it is coming from the ME (0x2C).
371 generatorID = 0x2C;
372 }
373 else
374 {
375 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
376 eventData1, eventData2, eventData3);
377 }
378 if (!p.fullyUnpacked())
379 {
380 return ipmi::responseReqDataLenInvalid();
381 }
382
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700383 // Send this request to the Redfish hooks to log it as a Redfish message
384 // instead. There is no need to add it to the SEL, so just return success.
385 intel_oem::ipmi::sel::checkRedfishHooks(
386 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
387 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700388
James Feist7aaf3fe2019-06-25 11:52:11 -0700389 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
390 eventData3)
391 {
392 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
393 }
394
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700395 return ipmi::responseSuccess();
396}
397
James Feist0cd014a2019-04-08 15:04:33 -0700398ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
James Feist25690252019-12-23 12:25:49 -0800399 ipmiSenGetSensorReading(boost::asio::yield_context yield, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700400{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700401 std::string connection;
402 std::string path;
403
404 auto status = getSensorConnection(sensnum, connection, path);
405 if (status)
406 {
James Feist0cd014a2019-04-08 15:04:33 -0700407 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700408 }
409
410 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800411 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700412 {
James Feist0cd014a2019-04-08 15:04:33 -0700413 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700414 }
415 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
416
417 if (sensorObject == sensorMap.end() ||
418 sensorObject->second.find("Value") == sensorObject->second.end())
419 {
James Feist0cd014a2019-04-08 15:04:33 -0700420 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700421 }
James Feist0cd014a2019-04-08 15:04:33 -0700422 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700423 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700424
Yong Li1f2eb5e2019-05-23 14:07:17 +0800425 double max = 0;
426 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700427 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700428
429 int16_t mValue = 0;
430 int16_t bValue = 0;
431 int8_t rExp = 0;
432 int8_t bExp = 0;
433 bool bSigned = false;
434
435 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
436 {
James Feist0cd014a2019-04-08 15:04:33 -0700437 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700438 }
439
James Feist0cd014a2019-04-08 15:04:33 -0700440 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700441 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700442 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700443 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700444 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800445 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700446
James Feist0cd014a2019-04-08 15:04:33 -0700447 uint8_t thresholds = 0;
448
449 auto warningObject =
450 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
451 if (warningObject != sensorMap.end())
452 {
453 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
454 auto alarmLow = warningObject->second.find("WarningAlarmLow");
455 if (alarmHigh != warningObject->second.end())
456 {
457 if (std::get<bool>(alarmHigh->second))
458 {
459 thresholds |= static_cast<uint8_t>(
460 IPMISensorReadingByte3::upperNonCritical);
461 }
462 }
463 if (alarmLow != warningObject->second.end())
464 {
465 if (std::get<bool>(alarmLow->second))
466 {
467 thresholds |= static_cast<uint8_t>(
468 IPMISensorReadingByte3::lowerNonCritical);
469 }
470 }
471 }
472
473 auto criticalObject =
474 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
475 if (criticalObject != sensorMap.end())
476 {
477 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
478 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
479 if (alarmHigh != criticalObject->second.end())
480 {
481 if (std::get<bool>(alarmHigh->second))
482 {
483 thresholds |=
484 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
485 }
486 }
487 if (alarmLow != criticalObject->second.end())
488 {
489 if (std::get<bool>(alarmLow->second))
490 {
491 thresholds |=
492 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
493 }
494 }
495 }
496
497 // no discrete as of today so optional byte is never returned
498 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700499}
500
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000501/** @brief implements the Set Sensor threshold command
502 * @param sensorNumber - sensor number
503 * @param lowerNonCriticalThreshMask
504 * @param lowerCriticalThreshMask
505 * @param lowerNonRecovThreshMask
506 * @param upperNonCriticalThreshMask
507 * @param upperCriticalThreshMask
508 * @param upperNonRecovThreshMask
509 * @param reserved
510 * @param lowerNonCritical - lower non-critical threshold
511 * @param lowerCritical - Lower critical threshold
512 * @param lowerNonRecoverable - Lower non recovarable threshold
513 * @param upperNonCritical - Upper non-critical threshold
514 * @param upperCritical - Upper critical
515 * @param upperNonRecoverable - Upper Non-recoverable
516 *
517 * @returns IPMI completion code
518 */
519ipmi::RspType<> ipmiSenSetSensorThresholds(
James Feist25690252019-12-23 12:25:49 -0800520 boost::asio::yield_context yield, uint8_t sensorNum,
521 bool lowerNonCriticalThreshMask, bool lowerCriticalThreshMask,
522 bool lowerNonRecovThreshMask, bool upperNonCriticalThreshMask,
523 bool upperCriticalThreshMask, bool upperNonRecovThreshMask,
524 uint2_t reserved, uint8_t lowerNonCritical, uint8_t lowerCritical,
525 uint8_t lowerNonRecoverable, uint8_t upperNonCritical,
526 uint8_t upperCritical, uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700527{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000528 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700529
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000530 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700531 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000532 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700533 }
534
535 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000536 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700537 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000538 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700539 }
540
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000541 // if none of the threshold mask are set, nothing to do
542 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
543 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
544 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700545 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000546 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700547 }
548
549 std::string connection;
550 std::string path;
551
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000552 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700553 if (status)
554 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000555 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700556 }
557 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800558 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700559 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000560 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700561 }
562
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700563 double max = 0;
564 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700565 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700566
567 int16_t mValue = 0;
568 int16_t bValue = 0;
569 int8_t rExp = 0;
570 int8_t bExp = 0;
571 bool bSigned = false;
572
573 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
574 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000575 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700576 }
577
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700578 // store a vector of property name, value to set, and interface
579 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
580
581 // define the indexes of the tuple
582 constexpr uint8_t propertyName = 0;
583 constexpr uint8_t thresholdValue = 1;
584 constexpr uint8_t interface = 2;
585 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000586 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700587 {
588 auto findThreshold =
589 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
590 if (findThreshold == sensorMap.end())
591 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000592 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700593 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000594 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700595 {
596 auto findLower = findThreshold->second.find("CriticalLow");
597 if (findLower == findThreshold->second.end())
598 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000599 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700600 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000601 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700602 findThreshold->first);
603 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000604 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700605 {
606 auto findUpper = findThreshold->second.find("CriticalHigh");
607 if (findUpper == findThreshold->second.end())
608 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000609 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700610 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000611 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700612 findThreshold->first);
613 }
614 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000615 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700616 {
617 auto findThreshold =
618 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
619 if (findThreshold == sensorMap.end())
620 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000621 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700622 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000623 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700624 {
625 auto findLower = findThreshold->second.find("WarningLow");
626 if (findLower == findThreshold->second.end())
627 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000628 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700629 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 findThreshold->first);
632 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000633 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700634 {
635 auto findUpper = findThreshold->second.find("WarningHigh");
636 if (findUpper == findThreshold->second.end())
637 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000638 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700639 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000640 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700641 findThreshold->first);
642 }
643 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644 for (const auto &property : thresholdsToSet)
645 {
646 // from section 36.3 in the IPMI Spec, assume all linear
647 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800648 (bValue * std::pow(10.0, bExp))) *
649 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700650 setDbusProperty(
651 *getSdBus(), connection, path, std::get<interface>(property),
652 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700653 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000654 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700655}
656
James Feist902c4c52019-04-16 14:51:31 -0700657IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700658{
James Feist902c4c52019-04-16 14:51:31 -0700659 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700660 auto warningInterface =
661 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
662 auto criticalInterface =
663 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
664
665 if ((warningInterface != sensorMap.end()) ||
666 (criticalInterface != sensorMap.end()))
667 {
668 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
669
670 if (sensorPair == sensorMap.end())
671 {
672 // should not have been able to find a sensor not implementing
673 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700674 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700675 }
676
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800677 double max = 0;
678 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700679 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700680
681 int16_t mValue = 0;
682 int16_t bValue = 0;
683 int8_t rExp = 0;
684 int8_t bExp = 0;
685 bool bSigned = false;
686
687 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
688 {
James Feist902c4c52019-04-16 14:51:31 -0700689 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700690 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700691 if (warningInterface != sensorMap.end())
692 {
693 auto &warningMap = warningInterface->second;
694
695 auto warningHigh = warningMap.find("WarningHigh");
696 auto warningLow = warningMap.find("WarningLow");
697
698 if (warningHigh != warningMap.end())
699 {
James Feist902c4c52019-04-16 14:51:31 -0700700
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700701 double value =
702 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700703 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700704 value, mValue, rExp, bValue, bExp, bSigned);
705 }
706 if (warningLow != warningMap.end())
707 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700708 double value =
709 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700710 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700711 value, mValue, rExp, bValue, bExp, bSigned);
712 }
713 }
714 if (criticalInterface != sensorMap.end())
715 {
716 auto &criticalMap = criticalInterface->second;
717
718 auto criticalHigh = criticalMap.find("CriticalHigh");
719 auto criticalLow = criticalMap.find("CriticalLow");
720
721 if (criticalHigh != criticalMap.end())
722 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700723 double value =
724 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700725 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700726 value, mValue, rExp, bValue, bExp, bSigned);
727 }
728 if (criticalLow != criticalMap.end())
729 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700730 double value =
731 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700732 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700733 value, mValue, rExp, bValue, bExp, bSigned);
734 }
735 }
736 }
James Feist902c4c52019-04-16 14:51:31 -0700737 return resp;
738}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700739
James Feist902c4c52019-04-16 14:51:31 -0700740ipmi::RspType<uint8_t, // readable
741 uint8_t, // lowerNCrit
742 uint8_t, // lowerCrit
743 uint8_t, // lowerNrecoverable
744 uint8_t, // upperNC
745 uint8_t, // upperCrit
746 uint8_t> // upperNRecoverable
James Feist25690252019-12-23 12:25:49 -0800747 ipmiSenGetSensorThresholds(boost::asio::yield_context yield,
748 uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700749{
750 std::string connection;
751 std::string path;
752
753 auto status = getSensorConnection(sensorNumber, connection, path);
754 if (status)
755 {
756 return ipmi::response(status);
757 }
758
759 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800760 if (!getSensorMap(yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700761 {
762 return ipmi::responseResponseError();
763 }
764
765 IPMIThresholds thresholdData;
766 try
767 {
768 thresholdData = getIPMIThresholds(sensorMap);
769 }
770 catch (std::exception &)
771 {
772 return ipmi::responseResponseError();
773 }
774
775 uint8_t readable = 0;
776 uint8_t lowerNC = 0;
777 uint8_t lowerCritical = 0;
778 uint8_t lowerNonRecoverable = 0;
779 uint8_t upperNC = 0;
780 uint8_t upperCritical = 0;
781 uint8_t upperNonRecoverable = 0;
782
783 if (thresholdData.warningHigh)
784 {
785 readable |=
786 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
787 upperNC = *thresholdData.warningHigh;
788 }
789 if (thresholdData.warningLow)
790 {
791 readable |=
792 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
793 lowerNC = *thresholdData.warningLow;
794 }
795
796 if (thresholdData.criticalHigh)
797 {
798 readable |=
799 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
800 upperCritical = *thresholdData.criticalHigh;
801 }
802 if (thresholdData.criticalLow)
803 {
804 readable |=
805 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
806 lowerCritical = *thresholdData.criticalLow;
807 }
808
809 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
810 lowerNonRecoverable, upperNC, upperCritical,
811 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700812}
813
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000814/** @brief implements the get Sensor event enable command
815 * @param sensorNumber - sensor number
816 *
817 * @returns IPMI completion code plus response data
818 * - enabled - Sensor Event messages
819 * - assertionEnabledLsb - Assertion event messages
820 * - assertionEnabledMsb - Assertion event messages
821 * - deassertionEnabledLsb - Deassertion event messages
822 * - deassertionEnabledMsb - Deassertion event messages
823 */
824
825ipmi::RspType<uint8_t, // enabled
826 uint8_t, // assertionEnabledLsb
827 uint8_t, // assertionEnabledMsb
828 uint8_t, // deassertionEnabledLsb
829 uint8_t> // deassertionEnabledMsb
James Feist25690252019-12-23 12:25:49 -0800830 ipmiSenGetSensorEventEnable(boost::asio::yield_context yield,
831 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700832{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700833 std::string connection;
834 std::string path;
835
Patrick Venturea41714c2019-09-25 16:59:41 -0700836 uint8_t enabled = 0;
837 uint8_t assertionEnabledLsb = 0;
838 uint8_t assertionEnabledMsb = 0;
839 uint8_t deassertionEnabledLsb = 0;
840 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000841
842 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700843 if (status)
844 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000845 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700846 }
847
848 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800849 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700850 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000851 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700852 }
853
854 auto warningInterface =
855 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
856 auto criticalInterface =
857 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700858 if ((warningInterface != sensorMap.end()) ||
859 (criticalInterface != sensorMap.end()))
860 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000861 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700862 IPMISensorEventEnableByte2::sensorScanningEnable);
863 if (warningInterface != sensorMap.end())
864 {
865 auto &warningMap = warningInterface->second;
866
867 auto warningHigh = warningMap.find("WarningHigh");
868 auto warningLow = warningMap.find("WarningLow");
869 if (warningHigh != warningMap.end())
870 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000871 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700872 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000873 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700874 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
875 }
876 if (warningLow != warningMap.end())
877 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000878 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700879 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000880 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700881 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
882 }
883 }
884 if (criticalInterface != sensorMap.end())
885 {
886 auto &criticalMap = criticalInterface->second;
887
888 auto criticalHigh = criticalMap.find("CriticalHigh");
889 auto criticalLow = criticalMap.find("CriticalLow");
890
891 if (criticalHigh != criticalMap.end())
892 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000893 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700894 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000895 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700896 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
897 }
898 if (criticalLow != criticalMap.end())
899 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000900 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700901 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000902 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700903 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
904 }
905 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700906 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000907
908 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
909 assertionEnabledMsb, deassertionEnabledLsb,
910 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700911}
912
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000913/** @brief implements the get Sensor event status command
914 * @param sensorNumber - sensor number, FFh = reserved
915 *
916 * @returns IPMI completion code plus response data
917 * - sensorEventStatus - Sensor Event messages state
918 * - assertions - Assertion event messages
919 * - deassertions - Deassertion event messages
920 */
921ipmi::RspType<uint8_t, // sensorEventStatus
922 std::bitset<16>, // assertions
923 std::bitset<16> // deassertion
924 >
James Feist25690252019-12-23 12:25:49 -0800925 ipmiSenGetSensorEventStatus(boost::asio::yield_context yield,
926 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700927{
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000928 if (sensorNum == 0xFF)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700929 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000930 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700931 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700932
933 std::string connection;
934 std::string path;
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000935 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700936 if (status)
937 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000938 phosphor::logging::log<phosphor::logging::level::ERR>(
939 "ipmiSenGetSensorEventStatus: Sensor connection Error",
940 phosphor::logging::entry("SENSOR=%d", sensorNum));
941 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700942 }
943
944 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800945 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700946 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000947 phosphor::logging::log<phosphor::logging::level::ERR>(
948 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
949 phosphor::logging::entry("SENSOR=%s", path.c_str()));
950 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700951 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700952 auto warningInterface =
953 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
954 auto criticalInterface =
955 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
956
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000957 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700958 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
959
James Feist392786a2019-03-19 13:36:10 -0700960 std::optional<bool> criticalDeassertHigh =
961 thresholdDeassertMap[path]["CriticalAlarmHigh"];
962 std::optional<bool> criticalDeassertLow =
963 thresholdDeassertMap[path]["CriticalAlarmLow"];
964 std::optional<bool> warningDeassertHigh =
965 thresholdDeassertMap[path]["WarningAlarmHigh"];
966 std::optional<bool> warningDeassertLow =
967 thresholdDeassertMap[path]["WarningAlarmLow"];
968
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000969 std::bitset<16> assertions = 0;
970 std::bitset<16> deassertions = 0;
971
James Feist392786a2019-03-19 13:36:10 -0700972 if (criticalDeassertHigh && !*criticalDeassertHigh)
973 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000974 deassertions.set(static_cast<size_t>(
975 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700976 }
977 if (criticalDeassertLow && !*criticalDeassertLow)
978 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000979 deassertions.set(static_cast<size_t>(
980 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -0700981 }
982 if (warningDeassertHigh && !*warningDeassertHigh)
983 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000984 deassertions.set(static_cast<size_t>(
985 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700986 }
987 if (warningDeassertLow && !*warningDeassertLow)
988 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000989 deassertions.set(static_cast<size_t>(
990 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700991 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700992 if ((warningInterface != sensorMap.end()) ||
993 (criticalInterface != sensorMap.end()))
994 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000995 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700996 IPMISensorEventEnableByte2::eventMessagesEnable);
997 if (warningInterface != sensorMap.end())
998 {
999 auto &warningMap = warningInterface->second;
1000
1001 auto warningHigh = warningMap.find("WarningAlarmHigh");
1002 auto warningLow = warningMap.find("WarningAlarmLow");
1003 auto warningHighAlarm = false;
1004 auto warningLowAlarm = false;
1005
1006 if (warningHigh != warningMap.end())
1007 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001008 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001009 }
1010 if (warningLow != warningMap.end())
1011 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001012 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001013 }
1014 if (warningHighAlarm)
1015 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001016 assertions.set(
1017 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1018 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001019 }
1020 if (warningLowAlarm)
1021 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001022 assertions.set(
1023 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1024 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001025 }
1026 }
1027 if (criticalInterface != sensorMap.end())
1028 {
1029 auto &criticalMap = criticalInterface->second;
1030
1031 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1032 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1033 auto criticalHighAlarm = false;
1034 auto criticalLowAlarm = false;
1035
1036 if (criticalHigh != criticalMap.end())
1037 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001038 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001039 }
1040 if (criticalLow != criticalMap.end())
1041 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001042 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001043 }
1044 if (criticalHighAlarm)
1045 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001046 assertions.set(
1047 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1048 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001049 }
1050 if (criticalLowAlarm)
1051 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001052 assertions.set(static_cast<size_t>(
1053 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001054 }
1055 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001056 }
1057
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001058 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001059}
1060
1061/* end sensor commands */
1062
1063/* storage commands */
1064
James Feist74c50c62019-08-14 14:18:41 -07001065ipmi::RspType<uint8_t, // sdr version
1066 uint16_t, // record count
1067 uint16_t, // free space
1068 uint32_t, // most recent addition
1069 uint32_t, // most recent erase
1070 uint8_t // operationSupport
1071 >
James Feist25690252019-12-23 12:25:49 -08001072 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001073{
James Feist74c50c62019-08-14 14:18:41 -07001074 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001075 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1076 {
James Feist74c50c62019-08-14 14:18:41 -07001077 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001078 }
1079
James Feist74c50c62019-08-14 14:18:41 -07001080 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001081 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001082 if (ret != ipmi::ccSuccess)
1083 {
1084 return ipmi::response(ret);
1085 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001086
James Feist74c50c62019-08-14 14:18:41 -07001087 uint16_t recordCount =
1088 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089
James Feist74c50c62019-08-14 14:18:41 -07001090 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001091 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001092
1093 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001094 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001095 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001096 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001097 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1098 unspecifiedFreeSpace, sdrLastAdd,
1099 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001100}
1101
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001102/** @brief implements the get SDR allocation info command
1103 *
1104 * @returns IPMI completion code plus response data
1105 * - allocUnits - Number of possible allocation units
1106 * - allocUnitSize - Allocation unit size in bytes.
1107 * - allocUnitFree - Number of free allocation units
1108 * - allocUnitLargestFree - Largest free block in allocation units
1109 * - maxRecordSize - Maximum record size in allocation units.
1110 */
1111ipmi::RspType<uint16_t, // allocUnits
1112 uint16_t, // allocUnitSize
1113 uint16_t, // allocUnitFree
1114 uint16_t, // allocUnitLargestFree
1115 uint8_t // maxRecordSize
1116 >
1117 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001119 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001120 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001121
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001122 constexpr uint16_t allocUnitFree = 0;
1123 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001124 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001125 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001126
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001127 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1128 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001129}
1130
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001131/** @brief implements the reserve SDR command
1132 * @returns IPMI completion code plus response data
1133 * - sdrReservationID
1134 */
1135ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001136{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001137 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001138 if (sdrReservationID == 0)
1139 {
1140 sdrReservationID++;
1141 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001142
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001143 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001144}
1145
James Feistb49a98a2019-04-16 13:48:09 -07001146ipmi::RspType<uint16_t, // next record ID
1147 std::vector<uint8_t> // payload
1148 >
James Feist25690252019-12-23 12:25:49 -08001149 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1150 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001151{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001152 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153
1154 // reservation required for partial reads with non zero offset into
1155 // record
James Feistb49a98a2019-04-16 13:48:09 -07001156 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001157 {
James Feistb49a98a2019-04-16 13:48:09 -07001158 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159 }
1160
1161 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1162 {
James Feistb49a98a2019-04-16 13:48:09 -07001163 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001164 }
1165
1166 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001167 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001168 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001169 {
James Feistb49a98a2019-04-16 13:48:09 -07001170 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001171 }
1172
James Feist74c50c62019-08-14 14:18:41 -07001173 size_t lastRecord =
1174 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001175 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001176 {
James Feistb49a98a2019-04-16 13:48:09 -07001177 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001178 }
James Feistb49a98a2019-04-16 13:48:09 -07001179 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001180 {
James Feistb49a98a2019-04-16 13:48:09 -07001181 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001182 }
1183
James Feistb49a98a2019-04-16 13:48:09 -07001184 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001185
James Feistb49a98a2019-04-16 13:48:09 -07001186 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001187 {
James Feist74c50c62019-08-14 14:18:41 -07001188 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001189 size_t fruIndex = recordID - sensorTree.size();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001190 if (fruIndex >= fruCount)
1191 {
James Feist74c50c62019-08-14 14:18:41 -07001192 // handle type 12 hardcoded records
1193 size_t type12Index = fruIndex - fruCount;
1194 if (type12Index >= ipmi::storage::type12Count ||
1195 offset > sizeof(Type12Record))
1196 {
1197 return ipmi::responseInvalidFieldRequest();
1198 }
1199 std::vector<uint8_t> record =
1200 ipmi::storage::getType12SDRs(type12Index, recordID);
1201 if (record.size() < (offset + bytesToRead))
1202 {
1203 bytesToRead = record.size() - offset;
1204 }
James Feistb49a98a2019-04-16 13:48:09 -07001205
James Feist74c50c62019-08-14 14:18:41 -07001206 recordData.insert(recordData.end(), record.begin() + offset,
1207 record.begin() + offset + bytesToRead);
1208 }
1209 else
1210 {
1211 // handle fru records
1212 get_sdr::SensorDataFruRecord data;
1213 if (offset > sizeof(data))
1214 {
1215 return ipmi::responseInvalidFieldRequest();
1216 }
James Feist25690252019-12-23 12:25:49 -08001217 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
James Feist74c50c62019-08-14 14:18:41 -07001218 if (ret != IPMI_CC_OK)
1219 {
1220 return ipmi::response(ret);
1221 }
1222 data.header.record_id_msb = recordID << 8;
1223 data.header.record_id_lsb = recordID & 0xFF;
1224 if (sizeof(data) < (offset + bytesToRead))
1225 {
1226 bytesToRead = sizeof(data) - offset;
1227 }
1228
1229 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1230 recordData.insert(recordData.end(), respStart,
1231 respStart + bytesToRead);
1232 }
James Feistb49a98a2019-04-16 13:48:09 -07001233
1234 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001235 }
1236
1237 std::string connection;
1238 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001239 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001240 for (const auto &sensor : sensorTree)
1241 {
1242 if (sensorIndex-- == 0)
1243 {
1244 if (!sensor.second.size())
1245 {
James Feistb49a98a2019-04-16 13:48:09 -07001246 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001247 }
1248 connection = sensor.second.begin()->first;
1249 path = sensor.first;
1250 break;
1251 }
1252 }
1253
1254 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -08001255 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001256 {
James Feistb49a98a2019-04-16 13:48:09 -07001257 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001258 }
James Feistb49a98a2019-04-16 13:48:09 -07001259 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001260 get_sdr::SensorDataFullRecord record = {0};
1261
James Feistb49a98a2019-04-16 13:48:09 -07001262 record.header.record_id_msb = recordID << 8;
1263 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001264 record.header.sdr_version = ipmiSdrVersion;
1265 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1266 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1267 sizeof(get_sdr::SensorDataRecordHeader);
1268 record.key.owner_id = 0x20;
1269 record.key.owner_lun = 0x0;
1270 record.key.sensor_number = sensornumber;
1271
James Feist7086a882019-03-13 10:46:00 -07001272 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001273 record.body.sensor_type = getSensorTypeFromPath(path);
1274 std::string type = getSensorTypeStringFromPath(path);
1275 auto typeCstr = type.c_str();
1276 auto findUnits = sensorUnits.find(typeCstr);
1277 if (findUnits != sensorUnits.end())
1278 {
1279 record.body.sensor_units_2_base =
1280 static_cast<uint8_t>(findUnits->second);
1281 } // else default 0x0 unspecified
1282
1283 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1284
1285 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1286 if (sensorObject == sensorMap.end())
1287 {
James Feistb49a98a2019-04-16 13:48:09 -07001288 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001289 }
1290
Patrick Venture262276f2019-10-18 13:27:59 -07001291 uint8_t entityId = 0;
1292 uint8_t entityInstance = 0x01;
1293
1294 // follow the association chain to get the parent board's entityid and
1295 // entityInstance
1296 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1297
1298 record.body.entity_id = entityId;
1299 record.body.entity_instance = entityInstance;
1300
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001301 auto maxObject = sensorObject->second.find("MaxValue");
1302 auto minObject = sensorObject->second.find("MinValue");
Josh Lehanca9dcbd2019-11-18 15:59:59 -08001303
1304 // If min and/or max are left unpopulated,
1305 // then default to what a signed byte would be, namely (-128,127) range.
1306 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1307 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001308 if (maxObject != sensorObject->second.end())
1309 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001310 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001311 }
1312
1313 if (minObject != sensorObject->second.end())
1314 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001315 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001316 }
1317
Yong Li1f2eb5e2019-05-23 14:07:17 +08001318 int16_t mValue = 0;
1319 int8_t rExp = 0;
1320 int16_t bValue = 0;
1321 int8_t bExp = 0;
1322 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001323
1324 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1325 {
James Feistb49a98a2019-04-16 13:48:09 -07001326 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001327 }
1328
Josh Lehan7cc9e472019-11-18 16:09:26 -08001329 // The record.body is a struct SensorDataFullRecordBody
1330 // from sensorhandler.hpp in phosphor-ipmi-host.
1331 // The meaning of these bits appears to come from
1332 // table 43.1 of the IPMI spec.
1333 // The above 5 sensor attributes are stuffed in as follows:
1334 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1335 // Byte 22-24 are for other purposes
1336 // Byte 25 = MMMMMMMM = LSB of M
1337 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1338 // Byte 27 = BBBBBBBB = LSB of B
1339 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1340 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1341 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1342
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001343 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1344 record.body.m_lsb = mValue & 0xFF;
1345
Josh Lehan7cc9e472019-11-18 16:09:26 -08001346 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1347 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1348
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001349 // move the smallest bit of the MSB into place (bit 9)
1350 // the MSbs are bits 7:8 in m_msb_and_tolerance
Josh Lehan7cc9e472019-11-18 16:09:26 -08001351 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001352
1353 record.body.b_lsb = bValue & 0xFF;
1354
Josh Lehan7cc9e472019-11-18 16:09:26 -08001355 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1356 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1357
1358 // move the smallest bit of the MSB into place (bit 9)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001359 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
Josh Lehan7cc9e472019-11-18 16:09:26 -08001360 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001361
Josh Lehan7cc9e472019-11-18 16:09:26 -08001362 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1363 uint8_t rExpBits = rExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001364
Josh Lehan7cc9e472019-11-18 16:09:26 -08001365 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1366 uint8_t bExpBits = bExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001367
Josh Lehan7cc9e472019-11-18 16:09:26 -08001368 // move rExp and bExp into place
1369 record.body.r_b_exponents =
1370 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1371
1372 // Set the analog reading byte interpretation accordingly
1373 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1374
1375 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1376 // These seem redundant, but derivable from the above 5 attributes
1377 // Original comment said "todo fill out rest of units"
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001378
1379 // populate sensor name from path
1380 std::string name;
1381 size_t nameStart = path.rfind("/");
1382 if (nameStart != std::string::npos)
1383 {
1384 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1385 }
1386
1387 std::replace(name.begin(), name.end(), '_', ' ');
1388 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1389 {
James Feist979a2322019-05-15 09:06:54 -07001390 // try to not truncate by replacing common words
1391 constexpr std::array<std::pair<const char *, const char *>, 2>
1392 replaceWords = {std::make_pair("Output", "Out"),
1393 std::make_pair("Input", "In")};
1394 for (const auto &[find, replace] : replaceWords)
1395 {
1396 boost::replace_all(name, find, replace);
1397 }
1398
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001399 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1400 }
1401 record.body.id_string_info = name.size();
1402 std::strncpy(record.body.id_string, name.c_str(),
1403 sizeof(record.body.id_string));
1404
James Feistc4b15bc2019-04-16 15:41:39 -07001405 IPMIThresholds thresholdData;
1406 try
1407 {
1408 thresholdData = getIPMIThresholds(sensorMap);
1409 }
1410 catch (std::exception &)
1411 {
1412 return ipmi::responseResponseError();
1413 }
1414
1415 if (thresholdData.criticalHigh)
1416 {
1417 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1418 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1419 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1420 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1421 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1422 record.body.discrete_reading_setting_mask[0] |=
1423 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1424 }
1425 if (thresholdData.warningHigh)
1426 {
1427 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1428 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1429 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1430 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1431 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1432 record.body.discrete_reading_setting_mask[0] |=
1433 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1434 }
1435 if (thresholdData.criticalLow)
1436 {
1437 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1438 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1439 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1440 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1441 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1442 record.body.discrete_reading_setting_mask[0] |=
1443 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1444 }
1445 if (thresholdData.warningLow)
1446 {
1447 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1448 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1449 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1450 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1451 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1452 record.body.discrete_reading_setting_mask[0] |=
1453 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1454 }
1455
1456 // everything that is readable is setable
1457 record.body.discrete_reading_setting_mask[1] =
1458 record.body.discrete_reading_setting_mask[0];
1459
James Feistb49a98a2019-04-16 13:48:09 -07001460 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001461 {
James Feistb49a98a2019-04-16 13:48:09 -07001462 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001463 }
1464
James Feistb49a98a2019-04-16 13:48:09 -07001465 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1466 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001467
James Feistb49a98a2019-04-16 13:48:09 -07001468 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001469}
1470/* end storage commands */
1471
1472void registerSensorFunctions()
1473{
1474 // get firmware version information
1475 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1476 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1477
1478 // <Get Sensor Type>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001479 ipmiPrintAndRegister(NETFUN_SENSOR, ipmi::sensor_event::cmdGetSensorType,
1480 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001481
1482 // <Set Sensor Reading and Event Status>
1483 ipmiPrintAndRegister(
Vernon Mauery98bbf692019-09-16 11:14:59 -07001484 NETFUN_SENSOR, ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001485 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1486
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001487 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001488 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1489 ipmi::sensor_event::cmdPlatformEvent,
1490 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001491
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001492 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001493 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1494 ipmi::sensor_event::cmdGetSensorReading,
1495 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001496
1497 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001498 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1499 ipmi::sensor_event::cmdGetSensorThreshold,
1500 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001501
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001502 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001503 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1504 ipmi::sensor_event::cmdSetSensorThreshold,
1505 ipmi::Privilege::Operator,
1506 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001507
1508 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001509 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1510 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001511 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001512
1513 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001514 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1515 ipmi::sensor_event::cmdGetSensorEventStatus,
1516 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001517
1518 // register all storage commands for both Sensor and Storage command
1519 // versions
1520
1521 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001522 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1523 ipmi::storage::cmdGetSdrRepositoryInfo,
1524 ipmi::Privilege::User,
1525 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001526
1527 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001528 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1529 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1530 ipmi::Privilege::User,
1531 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001532
1533 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001534 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1535 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001536 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001537
Vernon Mauery98bbf692019-09-16 11:14:59 -07001538 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1539 ipmi::storage::cmdReserveSdrRepository,
1540 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001541
1542 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001543 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1544 ipmi::sensor_event::cmdGetDeviceSdr,
1545 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001546
Vernon Mauery98bbf692019-09-16 11:14:59 -07001547 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1548 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1549 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001550}
1551} // namespace ipmi