blob: 06b4374164cd8b34e738b9f5e99e6e71fce3bd99 [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"
Patrick Venturec2a07d42020-05-30 16:35:03 -070024#include "types.hpp"
Patrick Venture31b35d52019-10-20 13:25:16 -070025
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070026#include <boost/algorithm/string.hpp>
27#include <boost/container/flat_map.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070028#include <ipmid/api.hpp>
29#include <ipmid/utils.hpp>
30#include <phosphor-logging/log.hpp>
31#include <sdbusplus/bus.hpp>
32
33#include <algorithm>
34#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070035#include <chrono>
36#include <cmath>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070037#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070038#include <iostream>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070039#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070040#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070041#include <optional>
Patrick Venturee6154022019-09-25 17:50:25 -070042#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070043#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070044#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070045#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070046
47namespace ipmi
48{
49using ManagedObjectType =
50 std::map<sdbusplus::message::object_path,
51 std::map<std::string, std::map<std::string, DbusVariant>>>;
52
James Feist25690252019-12-23 12:25:49 -080053static constexpr int sensorMapUpdatePeriod = 10;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070054
55constexpr size_t maxSDRTotalSize =
56 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
57constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
58
59static uint16_t sdrReservationID;
60static uint32_t sdrLastAdd = noTimestamp;
61static uint32_t sdrLastRemove = noTimestamp;
62
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053063SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070064static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
65
Jason M. Bills17add592018-11-12 14:30:12 -080066// Specify the comparison required to sort and find char* map objects
67struct CmpStr
68{
James Feistfcd2d3a2020-05-28 10:38:15 -070069 bool operator()(const char* a, const char* b) const
Jason M. Bills17add592018-11-12 14:30:12 -080070 {
71 return std::strcmp(a, b) < 0;
72 }
73};
James Feistfcd2d3a2020-05-28 10:38:15 -070074const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
Jason M. Bills17add592018-11-12 14:30:12 -080075 sensorUnits{{{"temperature", SensorUnits::degreesC},
76 {"voltage", SensorUnits::volts},
77 {"current", SensorUnits::amps},
78 {"fan_tach", SensorUnits::rpm},
79 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070080
81void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070082
83static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070084 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070085 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
86 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -070087 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070088 sensorTree.clear();
89 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
90 std::chrono::system_clock::now().time_since_epoch())
91 .count();
92 });
93
94static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070095 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070096 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
97 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -070098 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070099 sensorTree.clear();
100 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
101 std::chrono::system_clock::now().time_since_epoch())
102 .count();
103 });
104
James Feist392786a2019-03-19 13:36:10 -0700105// this keeps track of deassertions for sensor event status command. A
106// deasertion can only happen if an assertion was seen first.
107static boost::container::flat_map<
108 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
109 thresholdDeassertMap;
110
111static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700112 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700113 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
114 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feistfcd2d3a2020-05-28 10:38:15 -0700115 [](sdbusplus::message::message& m) {
James Feist392786a2019-03-19 13:36:10 -0700116 boost::container::flat_map<std::string, std::variant<bool, double>>
117 values;
118 m.read(std::string(), values);
119
120 auto findAssert =
James Feistfcd2d3a2020-05-28 10:38:15 -0700121 std::find_if(values.begin(), values.end(), [](const auto& pair) {
James Feist392786a2019-03-19 13:36:10 -0700122 return pair.first.find("Alarm") != std::string::npos;
123 });
124 if (findAssert != values.end())
125 {
126 auto ptr = std::get_if<bool>(&(findAssert->second));
127 if (ptr == nullptr)
128 {
129 phosphor::logging::log<phosphor::logging::level::ERR>(
130 "thresholdChanged: Assert non bool");
131 return;
132 }
133 if (*ptr)
134 {
135 phosphor::logging::log<phosphor::logging::level::INFO>(
136 "thresholdChanged: Assert",
137 phosphor::logging::entry("SENSOR=%s", m.get_path()));
138 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
139 }
140 else
141 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700142 auto& value =
James Feist392786a2019-03-19 13:36:10 -0700143 thresholdDeassertMap[m.get_path()][findAssert->first];
144 if (value)
145 {
146 phosphor::logging::log<phosphor::logging::level::INFO>(
147 "thresholdChanged: deassert",
148 phosphor::logging::entry("SENSOR=%s", m.get_path()));
149 value = *ptr;
150 }
151 }
152 }
153 });
154
James Feistfcd2d3a2020-05-28 10:38:15 -0700155static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
156 double& min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700157{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700158 max = 127;
159 min = -128;
160
James Feistaecaef72019-04-26 10:30:32 -0700161 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
162 auto critical =
163 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
164 auto warning =
165 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
166
167 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700168 {
James Feistaecaef72019-04-26 10:30:32 -0700169 auto maxMap = sensorObject->second.find("MaxValue");
170 auto minMap = sensorObject->second.find("MinValue");
171
172 if (maxMap != sensorObject->second.end())
173 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700174 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700175 }
176 if (minMap != sensorObject->second.end())
177 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700178 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700179 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700180 }
James Feistaecaef72019-04-26 10:30:32 -0700181 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700182 {
James Feistaecaef72019-04-26 10:30:32 -0700183 auto lower = critical->second.find("CriticalLow");
184 auto upper = critical->second.find("CriticalHigh");
185 if (lower != critical->second.end())
186 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700187 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700188 min = std::min(value, min);
189 }
190 if (upper != critical->second.end())
191 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700192 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700193 max = std::max(value, max);
194 }
195 }
196 if (warning != sensorMap.end())
197 {
198
199 auto lower = warning->second.find("WarningLow");
200 auto upper = warning->second.find("WarningHigh");
201 if (lower != warning->second.end())
202 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700203 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700204 min = std::min(value, min);
205 }
206 if (upper != warning->second.end())
207 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700208 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700209 max = std::max(value, max);
210 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700211 }
212}
213
James Feist25690252019-12-23 12:25:49 -0800214static bool getSensorMap(boost::asio::yield_context yield,
215 std::string sensorConnection, std::string sensorPath,
James Feistfcd2d3a2020-05-28 10:38:15 -0700216 SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700217{
218 static boost::container::flat_map<
219 std::string, std::chrono::time_point<std::chrono::steady_clock>>
220 updateTimeMap;
221
222 auto updateFind = updateTimeMap.find(sensorConnection);
223 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
224 if (updateFind != updateTimeMap.end())
225 {
226 lastUpdate = updateFind->second;
227 }
228
229 auto now = std::chrono::steady_clock::now();
230
231 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
232 .count() > sensorMapUpdatePeriod)
233 {
234 updateTimeMap[sensorConnection] = now;
235
Vernon Mauery15419dd2019-05-24 09:40:30 -0700236 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800237 boost::system::error_code ec;
238 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
239 yield, ec, sensorConnection.c_str(), "/",
240 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
241 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700242 {
243 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800244 "GetMangagedObjects for getSensorMap failed",
245 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
246
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700247 return false;
248 }
249
250 SensorCache[sensorConnection] = managedObjects;
251 }
252 auto connection = SensorCache.find(sensorConnection);
253 if (connection == SensorCache.end())
254 {
255 return false;
256 }
257 auto path = connection->second.find(sensorPath);
258 if (path == connection->second.end())
259 {
260 return false;
261 }
262 sensorMap = path->second;
263
264 return true;
265}
266
267/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700268namespace meHealth
269{
James Feistfcd2d3a2020-05-28 10:38:15 -0700270constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
271constexpr const char* path = "/xyz/openbmc_project/status/me";
272constexpr const char* interface = "xyz.openbmc_project.SetHealth";
273constexpr const char* method = "SetHealth";
274constexpr const char* critical = "critical";
275constexpr const char* warning = "warning";
276constexpr const char* ok = "ok";
James Feist7aaf3fe2019-06-25 11:52:11 -0700277} // namespace meHealth
278
279static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
280{
281 constexpr const std::array<uint8_t, 10> critical = {
282 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
283 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
284 0x1A};
285
286 std::string state;
287 if (std::find(critical.begin(), critical.end(), eventData2) !=
288 critical.end())
289 {
290 state = meHealth::critical;
291 }
292 // special case 0x3 as we only care about a few states
293 else if (eventData2 == 0x3)
294 {
295 if (eventData3 <= 0x2)
296 {
297 state = meHealth::warning;
298 }
299 else
300 {
301 return;
302 }
303 }
304 else if (std::find(warning.begin(), warning.end(), eventData2) !=
305 warning.end())
306 {
307 state = meHealth::warning;
308 }
309 else
310 {
311 return;
312 }
313 if (disable)
314 {
315 state = meHealth::ok;
316 }
317
318 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
319 auto setHealth =
320 dbus->new_method_call(meHealth::busname, meHealth::path,
321 meHealth::interface, meHealth::method);
322 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
323 try
324 {
325 dbus->call(setHealth);
326 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700327 catch (sdbusplus::exception_t&)
James Feist7aaf3fe2019-06-25 11:52:11 -0700328 {
329 phosphor::logging::log<phosphor::logging::level::ERR>(
330 "Failed to set ME Health");
331 }
332}
333
James Feistfcd2d3a2020-05-28 10:38:15 -0700334ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload& p)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700335{
James Feist7aaf3fe2019-06-25 11:52:11 -0700336 constexpr const uint8_t meId = 0x2C;
337 constexpr const uint8_t meSensorNum = 0x17;
338 constexpr const uint8_t disabled = 0x80;
339
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700340 uint8_t generatorID = 0;
341 uint8_t evmRev = 0;
342 uint8_t sensorType = 0;
343 uint8_t sensorNum = 0;
344 uint8_t eventType = 0;
345 uint8_t eventData1 = 0;
346 std::optional<uint8_t> eventData2 = 0;
347 std::optional<uint8_t> eventData3 = 0;
348
349 // todo: This check is supposed to be based on the incoming channel.
350 // e.g. system channel will provide upto 8 bytes including generator
351 // ID, but ipmb channel will provide only up to 7 bytes without the
352 // generator ID.
353 // Support for this check is coming in future patches, so for now just base
354 // it on if the first byte is the EvMRev (0x04).
355 if (p.size() && p.data()[0] == 0x04)
356 {
357 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
358 eventData2, eventData3);
359 // todo: the generator ID for this channel is supposed to come from the
360 // IPMB requesters slave address. Support for this is coming in future
361 // patches, so for now just assume it is coming from the ME (0x2C).
362 generatorID = 0x2C;
363 }
364 else
365 {
366 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
367 eventData1, eventData2, eventData3);
368 }
369 if (!p.fullyUnpacked())
370 {
371 return ipmi::responseReqDataLenInvalid();
372 }
373
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700374 // Send this request to the Redfish hooks to log it as a Redfish message
375 // instead. There is no need to add it to the SEL, so just return success.
376 intel_oem::ipmi::sel::checkRedfishHooks(
377 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
378 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700379
James Feist7aaf3fe2019-06-25 11:52:11 -0700380 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
381 eventData3)
382 {
383 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
384 }
385
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700386 return ipmi::responseSuccess();
387}
388
James Feist0cd014a2019-04-08 15:04:33 -0700389ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
James Feist25690252019-12-23 12:25:49 -0800390 ipmiSenGetSensorReading(boost::asio::yield_context yield, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700391{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700392 std::string connection;
393 std::string path;
394
395 auto status = getSensorConnection(sensnum, connection, path);
396 if (status)
397 {
James Feist0cd014a2019-04-08 15:04:33 -0700398 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700399 }
400
401 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800402 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700403 {
James Feist0cd014a2019-04-08 15:04:33 -0700404 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700405 }
406 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
407
408 if (sensorObject == sensorMap.end() ||
409 sensorObject->second.find("Value") == sensorObject->second.end())
410 {
James Feist0cd014a2019-04-08 15:04:33 -0700411 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700412 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700413 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700414 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700415
Yong Li1f2eb5e2019-05-23 14:07:17 +0800416 double max = 0;
417 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700418 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700419
420 int16_t mValue = 0;
421 int16_t bValue = 0;
422 int8_t rExp = 0;
423 int8_t bExp = 0;
424 bool bSigned = false;
425
426 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
427 {
James Feist0cd014a2019-04-08 15:04:33 -0700428 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700429 }
430
James Feist0cd014a2019-04-08 15:04:33 -0700431 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700432 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700433 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700434 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700435 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800436 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700437 bool notReading = std::isnan(reading);
438
439 if (!notReading)
440 {
441 auto availableObject =
442 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
443 if (availableObject != sensorMap.end())
444 {
445 auto findAvailable = availableObject->second.find("Available");
446 if (findAvailable != availableObject->second.end())
447 {
448 bool* available = std::get_if<bool>(&(findAvailable->second));
449 if (available && !(*available))
450 {
451 notReading = true;
452 }
453 }
454 }
455 }
456
457 if (notReading)
458 {
459 operation |= static_cast<uint8_t>(
460 IPMISensorReadingByte2::readingStateUnavailable);
461 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700462
James Feist0cd014a2019-04-08 15:04:33 -0700463 uint8_t thresholds = 0;
464
465 auto warningObject =
466 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
467 if (warningObject != sensorMap.end())
468 {
469 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
470 auto alarmLow = warningObject->second.find("WarningAlarmLow");
471 if (alarmHigh != warningObject->second.end())
472 {
473 if (std::get<bool>(alarmHigh->second))
474 {
475 thresholds |= static_cast<uint8_t>(
476 IPMISensorReadingByte3::upperNonCritical);
477 }
478 }
479 if (alarmLow != warningObject->second.end())
480 {
481 if (std::get<bool>(alarmLow->second))
482 {
483 thresholds |= static_cast<uint8_t>(
484 IPMISensorReadingByte3::lowerNonCritical);
485 }
486 }
487 }
488
489 auto criticalObject =
490 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
491 if (criticalObject != sensorMap.end())
492 {
493 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
494 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
495 if (alarmHigh != criticalObject->second.end())
496 {
497 if (std::get<bool>(alarmHigh->second))
498 {
499 thresholds |=
500 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
501 }
502 }
503 if (alarmLow != criticalObject->second.end())
504 {
505 if (std::get<bool>(alarmLow->second))
506 {
507 thresholds |=
508 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
509 }
510 }
511 }
512
513 // no discrete as of today so optional byte is never returned
514 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700515}
516
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000517/** @brief implements the Set Sensor threshold command
518 * @param sensorNumber - sensor number
519 * @param lowerNonCriticalThreshMask
520 * @param lowerCriticalThreshMask
521 * @param lowerNonRecovThreshMask
522 * @param upperNonCriticalThreshMask
523 * @param upperCriticalThreshMask
524 * @param upperNonRecovThreshMask
525 * @param reserved
526 * @param lowerNonCritical - lower non-critical threshold
527 * @param lowerCritical - Lower critical threshold
528 * @param lowerNonRecoverable - Lower non recovarable threshold
529 * @param upperNonCritical - Upper non-critical threshold
530 * @param upperCritical - Upper critical
531 * @param upperNonRecoverable - Upper Non-recoverable
532 *
533 * @returns IPMI completion code
534 */
535ipmi::RspType<> ipmiSenSetSensorThresholds(
James Feist25690252019-12-23 12:25:49 -0800536 boost::asio::yield_context yield, uint8_t sensorNum,
537 bool lowerNonCriticalThreshMask, bool lowerCriticalThreshMask,
538 bool lowerNonRecovThreshMask, bool upperNonCriticalThreshMask,
539 bool upperCriticalThreshMask, bool upperNonRecovThreshMask,
540 uint2_t reserved, uint8_t lowerNonCritical, uint8_t lowerCritical,
541 uint8_t lowerNonRecoverable, uint8_t upperNonCritical,
542 uint8_t upperCritical, uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700543{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000544 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700545
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000546 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700547 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000548 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700549 }
550
551 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000552 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700553 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000554 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700555 }
556
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000557 // if none of the threshold mask are set, nothing to do
558 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
559 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
560 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700561 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000562 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700563 }
564
565 std::string connection;
566 std::string path;
567
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000568 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700569 if (status)
570 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000571 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700572 }
573 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800574 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700575 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000576 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700577 }
578
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700579 double max = 0;
580 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700581 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700582
583 int16_t mValue = 0;
584 int16_t bValue = 0;
585 int8_t rExp = 0;
586 int8_t bExp = 0;
587 bool bSigned = false;
588
589 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
590 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000591 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700592 }
593
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700594 // store a vector of property name, value to set, and interface
595 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
596
597 // define the indexes of the tuple
598 constexpr uint8_t propertyName = 0;
599 constexpr uint8_t thresholdValue = 1;
600 constexpr uint8_t interface = 2;
601 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000602 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700603 {
604 auto findThreshold =
605 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
606 if (findThreshold == sensorMap.end())
607 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000608 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700609 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000610 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700611 {
612 auto findLower = findThreshold->second.find("CriticalLow");
613 if (findLower == 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("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700618 findThreshold->first);
619 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000620 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700621 {
622 auto findUpper = findThreshold->second.find("CriticalHigh");
623 if (findUpper == findThreshold->second.end())
624 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000625 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700626 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 findThreshold->first);
629 }
630 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000631 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700632 {
633 auto findThreshold =
634 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
635 if (findThreshold == sensorMap.end())
636 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000637 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700638 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000639 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700640 {
641 auto findLower = findThreshold->second.find("WarningLow");
642 if (findLower == 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("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700647 findThreshold->first);
648 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000649 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650 {
651 auto findUpper = findThreshold->second.find("WarningHigh");
652 if (findUpper == findThreshold->second.end())
653 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000654 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700655 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000656 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700657 findThreshold->first);
658 }
659 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700660 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700661 {
662 // from section 36.3 in the IPMI Spec, assume all linear
663 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800664 (bValue * std::pow(10.0, bExp))) *
665 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700666 setDbusProperty(
667 *getSdBus(), connection, path, std::get<interface>(property),
668 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700669 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000670 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700671}
672
James Feistfcd2d3a2020-05-28 10:38:15 -0700673IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700674{
James Feist902c4c52019-04-16 14:51:31 -0700675 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700676 auto warningInterface =
677 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
678 auto criticalInterface =
679 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
680
681 if ((warningInterface != sensorMap.end()) ||
682 (criticalInterface != sensorMap.end()))
683 {
684 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
685
686 if (sensorPair == sensorMap.end())
687 {
688 // should not have been able to find a sensor not implementing
689 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700690 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700691 }
692
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800693 double max = 0;
694 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700695 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700696
697 int16_t mValue = 0;
698 int16_t bValue = 0;
699 int8_t rExp = 0;
700 int8_t bExp = 0;
701 bool bSigned = false;
702
703 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
704 {
James Feist902c4c52019-04-16 14:51:31 -0700705 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700706 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700707 if (warningInterface != sensorMap.end())
708 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700709 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700710
711 auto warningHigh = warningMap.find("WarningHigh");
712 auto warningLow = warningMap.find("WarningLow");
713
714 if (warningHigh != warningMap.end())
715 {
James Feist902c4c52019-04-16 14:51:31 -0700716
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700717 double value =
718 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700719 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700720 value, mValue, rExp, bValue, bExp, bSigned);
721 }
722 if (warningLow != warningMap.end())
723 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700724 double value =
725 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700726 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700727 value, mValue, rExp, bValue, bExp, bSigned);
728 }
729 }
730 if (criticalInterface != sensorMap.end())
731 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700732 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700733
734 auto criticalHigh = criticalMap.find("CriticalHigh");
735 auto criticalLow = criticalMap.find("CriticalLow");
736
737 if (criticalHigh != criticalMap.end())
738 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700739 double value =
740 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700741 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700742 value, mValue, rExp, bValue, bExp, bSigned);
743 }
744 if (criticalLow != criticalMap.end())
745 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700746 double value =
747 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700748 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700749 value, mValue, rExp, bValue, bExp, bSigned);
750 }
751 }
752 }
James Feist902c4c52019-04-16 14:51:31 -0700753 return resp;
754}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700755
James Feist902c4c52019-04-16 14:51:31 -0700756ipmi::RspType<uint8_t, // readable
757 uint8_t, // lowerNCrit
758 uint8_t, // lowerCrit
759 uint8_t, // lowerNrecoverable
760 uint8_t, // upperNC
761 uint8_t, // upperCrit
762 uint8_t> // upperNRecoverable
James Feist25690252019-12-23 12:25:49 -0800763 ipmiSenGetSensorThresholds(boost::asio::yield_context yield,
764 uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700765{
766 std::string connection;
767 std::string path;
768
769 auto status = getSensorConnection(sensorNumber, connection, path);
770 if (status)
771 {
772 return ipmi::response(status);
773 }
774
775 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800776 if (!getSensorMap(yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700777 {
778 return ipmi::responseResponseError();
779 }
780
781 IPMIThresholds thresholdData;
782 try
783 {
784 thresholdData = getIPMIThresholds(sensorMap);
785 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700786 catch (std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700787 {
788 return ipmi::responseResponseError();
789 }
790
791 uint8_t readable = 0;
792 uint8_t lowerNC = 0;
793 uint8_t lowerCritical = 0;
794 uint8_t lowerNonRecoverable = 0;
795 uint8_t upperNC = 0;
796 uint8_t upperCritical = 0;
797 uint8_t upperNonRecoverable = 0;
798
799 if (thresholdData.warningHigh)
800 {
801 readable |=
802 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
803 upperNC = *thresholdData.warningHigh;
804 }
805 if (thresholdData.warningLow)
806 {
807 readable |=
808 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
809 lowerNC = *thresholdData.warningLow;
810 }
811
812 if (thresholdData.criticalHigh)
813 {
814 readable |=
815 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
816 upperCritical = *thresholdData.criticalHigh;
817 }
818 if (thresholdData.criticalLow)
819 {
820 readable |=
821 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
822 lowerCritical = *thresholdData.criticalLow;
823 }
824
825 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
826 lowerNonRecoverable, upperNC, upperCritical,
827 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700828}
829
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000830/** @brief implements the get Sensor event enable command
831 * @param sensorNumber - sensor number
832 *
833 * @returns IPMI completion code plus response data
834 * - enabled - Sensor Event messages
835 * - assertionEnabledLsb - Assertion event messages
836 * - assertionEnabledMsb - Assertion event messages
837 * - deassertionEnabledLsb - Deassertion event messages
838 * - deassertionEnabledMsb - Deassertion event messages
839 */
840
841ipmi::RspType<uint8_t, // enabled
842 uint8_t, // assertionEnabledLsb
843 uint8_t, // assertionEnabledMsb
844 uint8_t, // deassertionEnabledLsb
845 uint8_t> // deassertionEnabledMsb
James Feist25690252019-12-23 12:25:49 -0800846 ipmiSenGetSensorEventEnable(boost::asio::yield_context yield,
847 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700848{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700849 std::string connection;
850 std::string path;
851
Patrick Venturea41714c2019-09-25 16:59:41 -0700852 uint8_t enabled = 0;
853 uint8_t assertionEnabledLsb = 0;
854 uint8_t assertionEnabledMsb = 0;
855 uint8_t deassertionEnabledLsb = 0;
856 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000857
858 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700859 if (status)
860 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000861 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700862 }
863
864 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800865 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700866 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000867 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700868 }
869
870 auto warningInterface =
871 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
872 auto criticalInterface =
873 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700874 if ((warningInterface != sensorMap.end()) ||
875 (criticalInterface != sensorMap.end()))
876 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000877 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700878 IPMISensorEventEnableByte2::sensorScanningEnable);
879 if (warningInterface != sensorMap.end())
880 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700881 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700882
883 auto warningHigh = warningMap.find("WarningHigh");
884 auto warningLow = warningMap.find("WarningLow");
885 if (warningHigh != warningMap.end())
886 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000887 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700888 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000889 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700890 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
891 }
892 if (warningLow != warningMap.end())
893 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000894 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700895 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000896 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700897 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
898 }
899 }
900 if (criticalInterface != sensorMap.end())
901 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700902 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700903
904 auto criticalHigh = criticalMap.find("CriticalHigh");
905 auto criticalLow = criticalMap.find("CriticalLow");
906
907 if (criticalHigh != criticalMap.end())
908 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000909 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700910 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000911 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700912 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
913 }
914 if (criticalLow != criticalMap.end())
915 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000916 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700917 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000918 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700919 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
920 }
921 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700922 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000923
924 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
925 assertionEnabledMsb, deassertionEnabledLsb,
926 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700927}
928
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000929/** @brief implements the get Sensor event status command
930 * @param sensorNumber - sensor number, FFh = reserved
931 *
932 * @returns IPMI completion code plus response data
933 * - sensorEventStatus - Sensor Event messages state
934 * - assertions - Assertion event messages
935 * - deassertions - Deassertion event messages
936 */
937ipmi::RspType<uint8_t, // sensorEventStatus
938 std::bitset<16>, // assertions
939 std::bitset<16> // deassertion
940 >
James Feist25690252019-12-23 12:25:49 -0800941 ipmiSenGetSensorEventStatus(boost::asio::yield_context yield,
942 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700943{
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000944 if (sensorNum == 0xFF)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700945 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000946 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700947 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700948
949 std::string connection;
950 std::string path;
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000951 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700952 if (status)
953 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000954 phosphor::logging::log<phosphor::logging::level::ERR>(
955 "ipmiSenGetSensorEventStatus: Sensor connection Error",
956 phosphor::logging::entry("SENSOR=%d", sensorNum));
957 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700958 }
959
960 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800961 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700962 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000963 phosphor::logging::log<phosphor::logging::level::ERR>(
964 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
965 phosphor::logging::entry("SENSOR=%s", path.c_str()));
966 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700967 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700968 auto warningInterface =
969 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
970 auto criticalInterface =
971 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
972
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000973 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700974 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
975
James Feist392786a2019-03-19 13:36:10 -0700976 std::optional<bool> criticalDeassertHigh =
977 thresholdDeassertMap[path]["CriticalAlarmHigh"];
978 std::optional<bool> criticalDeassertLow =
979 thresholdDeassertMap[path]["CriticalAlarmLow"];
980 std::optional<bool> warningDeassertHigh =
981 thresholdDeassertMap[path]["WarningAlarmHigh"];
982 std::optional<bool> warningDeassertLow =
983 thresholdDeassertMap[path]["WarningAlarmLow"];
984
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000985 std::bitset<16> assertions = 0;
986 std::bitset<16> deassertions = 0;
987
James Feist392786a2019-03-19 13:36:10 -0700988 if (criticalDeassertHigh && !*criticalDeassertHigh)
989 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000990 deassertions.set(static_cast<size_t>(
991 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700992 }
993 if (criticalDeassertLow && !*criticalDeassertLow)
994 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000995 deassertions.set(static_cast<size_t>(
996 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -0700997 }
998 if (warningDeassertHigh && !*warningDeassertHigh)
999 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001000 deassertions.set(static_cast<size_t>(
1001 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001002 }
1003 if (warningDeassertLow && !*warningDeassertLow)
1004 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001005 deassertions.set(static_cast<size_t>(
1006 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001007 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001008 if ((warningInterface != sensorMap.end()) ||
1009 (criticalInterface != sensorMap.end()))
1010 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001011 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001012 IPMISensorEventEnableByte2::eventMessagesEnable);
1013 if (warningInterface != sensorMap.end())
1014 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001015 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001016
1017 auto warningHigh = warningMap.find("WarningAlarmHigh");
1018 auto warningLow = warningMap.find("WarningAlarmLow");
1019 auto warningHighAlarm = false;
1020 auto warningLowAlarm = false;
1021
1022 if (warningHigh != warningMap.end())
1023 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001024 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001025 }
1026 if (warningLow != warningMap.end())
1027 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001028 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001029 }
1030 if (warningHighAlarm)
1031 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001032 assertions.set(
1033 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1034 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001035 }
1036 if (warningLowAlarm)
1037 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001038 assertions.set(
1039 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1040 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001041 }
1042 }
1043 if (criticalInterface != sensorMap.end())
1044 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001045 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001046
1047 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1048 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1049 auto criticalHighAlarm = false;
1050 auto criticalLowAlarm = false;
1051
1052 if (criticalHigh != criticalMap.end())
1053 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001054 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001055 }
1056 if (criticalLow != criticalMap.end())
1057 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001058 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001059 }
1060 if (criticalHighAlarm)
1061 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001062 assertions.set(
1063 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1064 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001065 }
1066 if (criticalLowAlarm)
1067 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001068 assertions.set(static_cast<size_t>(
1069 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001070 }
1071 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001072 }
1073
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001074 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001075}
1076
1077/* end sensor commands */
1078
1079/* storage commands */
1080
James Feist74c50c62019-08-14 14:18:41 -07001081ipmi::RspType<uint8_t, // sdr version
1082 uint16_t, // record count
1083 uint16_t, // free space
1084 uint32_t, // most recent addition
1085 uint32_t, // most recent erase
1086 uint8_t // operationSupport
1087 >
James Feist25690252019-12-23 12:25:49 -08001088 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089{
James Feist74c50c62019-08-14 14:18:41 -07001090 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001091 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1092 {
James Feist74c50c62019-08-14 14:18:41 -07001093 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001094 }
1095
James Feist74c50c62019-08-14 14:18:41 -07001096 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001097 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001098 if (ret != ipmi::ccSuccess)
1099 {
1100 return ipmi::response(ret);
1101 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001102
James Feist74c50c62019-08-14 14:18:41 -07001103 uint16_t recordCount =
1104 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001105
James Feist74c50c62019-08-14 14:18:41 -07001106 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001107 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001108
1109 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001110 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001111 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001112 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001113 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1114 unspecifiedFreeSpace, sdrLastAdd,
1115 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001116}
1117
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001118/** @brief implements the get SDR allocation info command
1119 *
1120 * @returns IPMI completion code plus response data
1121 * - allocUnits - Number of possible allocation units
1122 * - allocUnitSize - Allocation unit size in bytes.
1123 * - allocUnitFree - Number of free allocation units
1124 * - allocUnitLargestFree - Largest free block in allocation units
1125 * - maxRecordSize - Maximum record size in allocation units.
1126 */
1127ipmi::RspType<uint16_t, // allocUnits
1128 uint16_t, // allocUnitSize
1129 uint16_t, // allocUnitFree
1130 uint16_t, // allocUnitLargestFree
1131 uint8_t // maxRecordSize
1132 >
1133 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001134{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001135 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001136 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001137
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001138 constexpr uint16_t allocUnitFree = 0;
1139 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001140 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001141 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001142
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001143 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1144 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001145}
1146
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001147/** @brief implements the reserve SDR command
1148 * @returns IPMI completion code plus response data
1149 * - sdrReservationID
1150 */
1151ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001152{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001154 if (sdrReservationID == 0)
1155 {
1156 sdrReservationID++;
1157 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001158
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001159 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001160}
1161
James Feistb49a98a2019-04-16 13:48:09 -07001162ipmi::RspType<uint16_t, // next record ID
1163 std::vector<uint8_t> // payload
1164 >
James Feist25690252019-12-23 12:25:49 -08001165 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1166 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001168 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001169
1170 // reservation required for partial reads with non zero offset into
1171 // record
James Feistb49a98a2019-04-16 13:48:09 -07001172 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173 {
James Feistb49a98a2019-04-16 13:48:09 -07001174 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001175 }
1176
1177 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1178 {
James Feistb49a98a2019-04-16 13:48:09 -07001179 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001180 }
1181
1182 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001183 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001184 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001185 {
James Feistb49a98a2019-04-16 13:48:09 -07001186 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001187 }
1188
Yong Lifee5e4c2020-01-17 19:36:29 +08001189 size_t lastRecord = sensorTree.size() + fruCount +
1190 ipmi::storage::type12Count +
1191 ipmi::storage::nmDiscoverySDRCount - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001192 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001193 {
James Feistb49a98a2019-04-16 13:48:09 -07001194 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001195 }
James Feistb49a98a2019-04-16 13:48:09 -07001196 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001197 {
James Feistb49a98a2019-04-16 13:48:09 -07001198 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001199 }
1200
James Feistb49a98a2019-04-16 13:48:09 -07001201 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001202
James Feistb49a98a2019-04-16 13:48:09 -07001203 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001204 {
James Feist74c50c62019-08-14 14:18:41 -07001205 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001206 size_t fruIndex = recordID - sensorTree.size();
Yong Lifee5e4c2020-01-17 19:36:29 +08001207 size_t type12End = fruCount + ipmi::storage::type12Count;
1208
1209 if (fruIndex >= type12End)
1210 {
1211 // NM discovery SDR
1212 size_t nmDiscoveryIndex = fruIndex - type12End;
1213 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount ||
1214 offset > sizeof(NMDiscoveryRecord))
1215 {
1216 return ipmi::responseInvalidFieldRequest();
1217 }
1218
1219 std::vector<uint8_t> record =
1220 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
1221 if (record.size() < (offset + bytesToRead))
1222 {
1223 bytesToRead = record.size() - offset;
1224 }
1225 recordData.insert(recordData.end(), record.begin() + offset,
1226 record.begin() + offset + bytesToRead);
1227 }
1228 else if (fruIndex >= fruCount)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001229 {
James Feist74c50c62019-08-14 14:18:41 -07001230 // handle type 12 hardcoded records
1231 size_t type12Index = fruIndex - fruCount;
1232 if (type12Index >= ipmi::storage::type12Count ||
1233 offset > sizeof(Type12Record))
1234 {
1235 return ipmi::responseInvalidFieldRequest();
1236 }
1237 std::vector<uint8_t> record =
1238 ipmi::storage::getType12SDRs(type12Index, recordID);
1239 if (record.size() < (offset + bytesToRead))
1240 {
1241 bytesToRead = record.size() - offset;
1242 }
James Feistb49a98a2019-04-16 13:48:09 -07001243
James Feist74c50c62019-08-14 14:18:41 -07001244 recordData.insert(recordData.end(), record.begin() + offset,
1245 record.begin() + offset + bytesToRead);
1246 }
1247 else
1248 {
1249 // handle fru records
1250 get_sdr::SensorDataFruRecord data;
1251 if (offset > sizeof(data))
1252 {
1253 return ipmi::responseInvalidFieldRequest();
1254 }
James Feist25690252019-12-23 12:25:49 -08001255 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
James Feist74c50c62019-08-14 14:18:41 -07001256 if (ret != IPMI_CC_OK)
1257 {
1258 return ipmi::response(ret);
1259 }
1260 data.header.record_id_msb = recordID << 8;
1261 data.header.record_id_lsb = recordID & 0xFF;
1262 if (sizeof(data) < (offset + bytesToRead))
1263 {
1264 bytesToRead = sizeof(data) - offset;
1265 }
1266
James Feistfcd2d3a2020-05-28 10:38:15 -07001267 uint8_t* respStart = reinterpret_cast<uint8_t*>(&data) + offset;
James Feist74c50c62019-08-14 14:18:41 -07001268 recordData.insert(recordData.end(), respStart,
1269 respStart + bytesToRead);
1270 }
James Feistb49a98a2019-04-16 13:48:09 -07001271
1272 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001273 }
1274
1275 std::string connection;
1276 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001277 uint16_t sensorIndex = recordID;
James Feistfcd2d3a2020-05-28 10:38:15 -07001278 for (const auto& sensor : sensorTree)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001279 {
1280 if (sensorIndex-- == 0)
1281 {
1282 if (!sensor.second.size())
1283 {
James Feistb49a98a2019-04-16 13:48:09 -07001284 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001285 }
1286 connection = sensor.second.begin()->first;
1287 path = sensor.first;
1288 break;
1289 }
1290 }
1291
1292 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -08001293 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001294 {
James Feistb49a98a2019-04-16 13:48:09 -07001295 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001296 }
James Feistb49a98a2019-04-16 13:48:09 -07001297 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001298 get_sdr::SensorDataFullRecord record = {0};
1299
James Feistb49a98a2019-04-16 13:48:09 -07001300 record.header.record_id_msb = recordID << 8;
1301 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001302 record.header.sdr_version = ipmiSdrVersion;
1303 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1304 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1305 sizeof(get_sdr::SensorDataRecordHeader);
1306 record.key.owner_id = 0x20;
1307 record.key.owner_lun = 0x0;
1308 record.key.sensor_number = sensornumber;
1309
James Feist7086a882019-03-13 10:46:00 -07001310 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001311 record.body.sensor_type = getSensorTypeFromPath(path);
1312 std::string type = getSensorTypeStringFromPath(path);
1313 auto typeCstr = type.c_str();
1314 auto findUnits = sensorUnits.find(typeCstr);
1315 if (findUnits != sensorUnits.end())
1316 {
1317 record.body.sensor_units_2_base =
1318 static_cast<uint8_t>(findUnits->second);
1319 } // else default 0x0 unspecified
1320
1321 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1322
1323 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1324 if (sensorObject == sensorMap.end())
1325 {
James Feistb49a98a2019-04-16 13:48:09 -07001326 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001327 }
1328
Patrick Venture262276f2019-10-18 13:27:59 -07001329 uint8_t entityId = 0;
1330 uint8_t entityInstance = 0x01;
1331
1332 // follow the association chain to get the parent board's entityid and
1333 // entityInstance
1334 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1335
1336 record.body.entity_id = entityId;
1337 record.body.entity_instance = entityInstance;
1338
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001339 auto maxObject = sensorObject->second.find("MaxValue");
1340 auto minObject = sensorObject->second.find("MinValue");
Josh Lehanca9dcbd2019-11-18 15:59:59 -08001341
1342 // If min and/or max are left unpopulated,
1343 // then default to what a signed byte would be, namely (-128,127) range.
1344 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1345 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001346 if (maxObject != sensorObject->second.end())
1347 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001348 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001349 }
1350
1351 if (minObject != sensorObject->second.end())
1352 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001353 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001354 }
1355
Yong Li1f2eb5e2019-05-23 14:07:17 +08001356 int16_t mValue = 0;
1357 int8_t rExp = 0;
1358 int16_t bValue = 0;
1359 int8_t bExp = 0;
1360 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001361
1362 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1363 {
James Feistb49a98a2019-04-16 13:48:09 -07001364 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001365 }
1366
Josh Lehan7cc9e472019-11-18 16:09:26 -08001367 // The record.body is a struct SensorDataFullRecordBody
1368 // from sensorhandler.hpp in phosphor-ipmi-host.
1369 // The meaning of these bits appears to come from
1370 // table 43.1 of the IPMI spec.
1371 // The above 5 sensor attributes are stuffed in as follows:
1372 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1373 // Byte 22-24 are for other purposes
1374 // Byte 25 = MMMMMMMM = LSB of M
1375 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1376 // Byte 27 = BBBBBBBB = LSB of B
1377 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1378 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1379 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1380
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001381 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1382 record.body.m_lsb = mValue & 0xFF;
1383
Josh Lehan7cc9e472019-11-18 16:09:26 -08001384 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1385 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1386
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001387 // move the smallest bit of the MSB into place (bit 9)
1388 // the MSbs are bits 7:8 in m_msb_and_tolerance
Josh Lehan7cc9e472019-11-18 16:09:26 -08001389 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001390
1391 record.body.b_lsb = bValue & 0xFF;
1392
Josh Lehan7cc9e472019-11-18 16:09:26 -08001393 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1394 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1395
1396 // move the smallest bit of the MSB into place (bit 9)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001397 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
Josh Lehan7cc9e472019-11-18 16:09:26 -08001398 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001399
Josh Lehan7cc9e472019-11-18 16:09:26 -08001400 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1401 uint8_t rExpBits = rExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001402
Josh Lehan7cc9e472019-11-18 16:09:26 -08001403 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1404 uint8_t bExpBits = bExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001405
Josh Lehan7cc9e472019-11-18 16:09:26 -08001406 // move rExp and bExp into place
1407 record.body.r_b_exponents =
1408 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1409
1410 // Set the analog reading byte interpretation accordingly
1411 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1412
1413 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1414 // These seem redundant, but derivable from the above 5 attributes
1415 // Original comment said "todo fill out rest of units"
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001416
1417 // populate sensor name from path
1418 std::string name;
1419 size_t nameStart = path.rfind("/");
1420 if (nameStart != std::string::npos)
1421 {
1422 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1423 }
1424
1425 std::replace(name.begin(), name.end(), '_', ' ');
1426 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1427 {
James Feist979a2322019-05-15 09:06:54 -07001428 // try to not truncate by replacing common words
James Feistfcd2d3a2020-05-28 10:38:15 -07001429 constexpr std::array<std::pair<const char*, const char*>, 2>
James Feist979a2322019-05-15 09:06:54 -07001430 replaceWords = {std::make_pair("Output", "Out"),
1431 std::make_pair("Input", "In")};
James Feistfcd2d3a2020-05-28 10:38:15 -07001432 for (const auto& [find, replace] : replaceWords)
James Feist979a2322019-05-15 09:06:54 -07001433 {
1434 boost::replace_all(name, find, replace);
1435 }
1436
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001437 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1438 }
1439 record.body.id_string_info = name.size();
1440 std::strncpy(record.body.id_string, name.c_str(),
1441 sizeof(record.body.id_string));
1442
James Feistc4b15bc2019-04-16 15:41:39 -07001443 IPMIThresholds thresholdData;
1444 try
1445 {
1446 thresholdData = getIPMIThresholds(sensorMap);
1447 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001448 catch (std::exception&)
James Feistc4b15bc2019-04-16 15:41:39 -07001449 {
1450 return ipmi::responseResponseError();
1451 }
1452
1453 if (thresholdData.criticalHigh)
1454 {
1455 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1456 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
Rashmi RV963a95b2020-01-27 15:09:17 +05301457 IPMISensorEventEnableThresholds::criticalThreshold);
1458 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
James Feistc4b15bc2019-04-16 15:41:39 -07001459 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1460 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1461 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1462 record.body.discrete_reading_setting_mask[0] |=
1463 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1464 }
1465 if (thresholdData.warningHigh)
1466 {
1467 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
Rashmi RV963a95b2020-01-27 15:09:17 +05301468 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1469 IPMISensorEventEnableThresholds::nonCriticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001470 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1471 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1472 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1473 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1474 record.body.discrete_reading_setting_mask[0] |=
1475 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1476 }
1477 if (thresholdData.criticalLow)
1478 {
1479 record.body.lower_critical_threshold = *thresholdData.criticalLow;
Rashmi RV963a95b2020-01-27 15:09:17 +05301480 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1481 IPMISensorEventEnableThresholds::criticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001482 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1483 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1484 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1485 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1486 record.body.discrete_reading_setting_mask[0] |=
1487 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1488 }
1489 if (thresholdData.warningLow)
1490 {
1491 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
Rashmi RV963a95b2020-01-27 15:09:17 +05301492 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1493 IPMISensorEventEnableThresholds::nonCriticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001494 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1495 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1496 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1497 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1498 record.body.discrete_reading_setting_mask[0] |=
1499 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1500 }
1501
1502 // everything that is readable is setable
1503 record.body.discrete_reading_setting_mask[1] =
1504 record.body.discrete_reading_setting_mask[0];
1505
James Feistb49a98a2019-04-16 13:48:09 -07001506 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001507 {
James Feistb49a98a2019-04-16 13:48:09 -07001508 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001509 }
1510
James Feistfcd2d3a2020-05-28 10:38:15 -07001511 uint8_t* respStart = reinterpret_cast<uint8_t*>(&record) + offset;
James Feistb49a98a2019-04-16 13:48:09 -07001512 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001513
James Feistb49a98a2019-04-16 13:48:09 -07001514 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001515}
1516/* end storage commands */
1517
1518void registerSensorFunctions()
1519{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001520 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001521 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1522 ipmi::sensor_event::cmdPlatformEvent,
1523 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001524
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001525 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001526 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1527 ipmi::sensor_event::cmdGetSensorReading,
1528 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001529
1530 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001531 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1532 ipmi::sensor_event::cmdGetSensorThreshold,
1533 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001534
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001535 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001536 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1537 ipmi::sensor_event::cmdSetSensorThreshold,
1538 ipmi::Privilege::Operator,
1539 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001540
1541 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001542 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1543 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001544 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001545
1546 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001547 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1548 ipmi::sensor_event::cmdGetSensorEventStatus,
1549 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001550
1551 // register all storage commands for both Sensor and Storage command
1552 // versions
1553
1554 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001555 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1556 ipmi::storage::cmdGetSdrRepositoryInfo,
1557 ipmi::Privilege::User,
1558 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001559
1560 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001561 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1562 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1563 ipmi::Privilege::User,
1564 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001565
1566 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001567 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1568 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001569 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001570
Vernon Mauery98bbf692019-09-16 11:14:59 -07001571 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1572 ipmi::storage::cmdReserveSdrRepository,
1573 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001574
1575 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001576 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1577 ipmi::sensor_event::cmdGetDeviceSdr,
1578 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001579
Vernon Mauery98bbf692019-09-16 11:14:59 -07001580 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1581 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1582 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001583}
1584} // namespace ipmi