blob: 6cc34f92843935275e3e392ffaca68f89fc7a185 [file] [log] [blame]
Brandon Kim9cf85622019-06-19 12:05:08 -07001#include "config.h"
2
Patrick Venture46470a32018-09-07 19:26:25 -07003#include "sensorhandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07004
Patrick Venture99bf1c42019-08-23 09:02:13 -07005#include "entity_map_json.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07006#include "fruread.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07007
Tomd700e762016-09-20 18:24:13 +05308#include <mapper.h>
Chris Austen10ccc0f2015-12-10 18:27:04 -06009#include <systemd/sd-bus.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070010
11#include <bitset>
Patrick Venture586d35b2018-09-07 19:56:18 -070012#include <cmath>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070013#include <cstring>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070014#include <ipmid/api.hpp>
Vernon Mauery33250242019-03-12 16:49:26 -070015#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070016#include <ipmid/utils.hpp>
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050017#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070018#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070019#include <sdbusplus/message/types.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070020#include <set>
21#include <xyz/openbmc_project/Common/error.hpp>
22#include <xyz/openbmc_project/Sensor/Value/server.hpp>
23
Ratan Guptae0cc8552018-01-22 14:23:04 +053024static constexpr uint8_t fruInventoryDevice = 0x10;
25static constexpr uint8_t IPMIFruInventory = 0x02;
26static constexpr uint8_t BMCSlaveAddress = 0x20;
27
Patrick Venture0b02be92018-08-31 11:55:55 -070028extern int updateSensorRecordFromSSRAESC(const void*);
29extern sd_bus* bus;
Patrick Venturedb0cbe62019-09-09 14:47:22 -070030
31namespace ipmi
32{
33namespace sensor
34{
35extern const IdInfoMap sensors;
36} // namespace sensor
37} // namespace ipmi
38
Ratan Guptae0cc8552018-01-22 14:23:04 +053039extern const FruMap frus;
40
Tom Josephbe703f72017-03-09 12:34:35 +053041using namespace phosphor::logging;
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050042using InternalFailure =
43 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austenac4604a2015-10-13 12:43:27 -050044
Patrick Venture0b02be92018-08-31 11:55:55 -070045void register_netfn_sen_functions() __attribute__((constructor));
Chris Austenac4604a2015-10-13 12:43:27 -050046
Patrick Venture0b02be92018-08-31 11:55:55 -070047struct sensorTypemap_t
48{
Chris Austen0012e9b2015-10-22 01:37:46 -050049 uint8_t number;
Chris Austend7cf0e42015-11-07 14:27:12 -060050 uint8_t typecode;
Chris Austen0012e9b2015-10-22 01:37:46 -050051 char dbusname[32];
Patrick Venture0b02be92018-08-31 11:55:55 -070052};
Chris Austen0012e9b2015-10-22 01:37:46 -050053
Chris Austen0012e9b2015-10-22 01:37:46 -050054sensorTypemap_t g_SensorTypeMap[] = {
55
Chris Austend7cf0e42015-11-07 14:27:12 -060056 {0x01, 0x6F, "Temp"},
57 {0x0C, 0x6F, "DIMM"},
58 {0x0C, 0x6F, "MEMORY_BUFFER"},
59 {0x07, 0x6F, "PROC"},
60 {0x07, 0x6F, "CORE"},
61 {0x07, 0x6F, "CPU"},
62 {0x0F, 0x6F, "BootProgress"},
Patrick Venture0b02be92018-08-31 11:55:55 -070063 {0xe9, 0x09, "OccStatus"}, // E9 is an internal mapping to handle sensor
64 // type code os 0x09
Chris Austend7cf0e42015-11-07 14:27:12 -060065 {0xC3, 0x6F, "BootCount"},
66 {0x1F, 0x6F, "OperatingSystemStatus"},
Chris Austen800ba712015-12-03 15:31:00 -060067 {0x12, 0x6F, "SYSTEM_EVENT"},
68 {0xC7, 0x03, "SYSTEM"},
69 {0xC7, 0x03, "MAIN_PLANAR"},
Chris Austen10ccc0f2015-12-10 18:27:04 -060070 {0xC2, 0x6F, "PowerCap"},
Tom Joseph558184e2017-09-01 13:45:05 +053071 {0x0b, 0xCA, "PowerSupplyRedundancy"},
Jayanth Othayoth0661beb2017-03-22 06:00:58 -050072 {0xDA, 0x03, "TurboAllowed"},
Tom Joseph558184e2017-09-01 13:45:05 +053073 {0xD8, 0xC8, "PowerSupplyDerating"},
Chris Austend7cf0e42015-11-07 14:27:12 -060074 {0xFF, 0x00, ""},
Chris Austen0012e9b2015-10-22 01:37:46 -050075};
76
Patrick Venture0b02be92018-08-31 11:55:55 -070077struct sensor_data_t
78{
Chris Austenac4604a2015-10-13 12:43:27 -050079 uint8_t sennum;
Patrick Venture0b02be92018-08-31 11:55:55 -070080} __attribute__((packed));
Chris Austenac4604a2015-10-13 12:43:27 -050081
Lei YU14a47812021-09-17 15:58:04 +080082using SDRCacheMap = std::unordered_map<uint8_t, get_sdr::SensorDataFullRecord>;
83SDRCacheMap sdrCacheMap __attribute__((init_priority(101)));
84
85using SensorThresholdMap =
86 std::unordered_map<uint8_t, get_sdr::GetSensorThresholdsResponse>;
87SensorThresholdMap sensorThresholdMap __attribute__((init_priority(101)));
88
Lei YU962e68b2021-09-16 16:25:34 +080089#ifdef FEATURE_SENSORS_CACHE
Lei YUbe5c6b22021-09-16 15:46:20 +080090std::map<uint8_t, std::unique_ptr<sdbusplus::bus::match::match>>
91 sensorAddedMatches __attribute__((init_priority(101)));
92std::map<uint8_t, std::unique_ptr<sdbusplus::bus::match::match>>
93 sensorUpdatedMatches __attribute__((init_priority(101)));
94
Lei YU97140502021-09-17 13:49:43 +080095ipmi::sensor::SensorCacheMap sensorCacheMap __attribute__((init_priority(101)));
Lei YU8c2c0482021-09-16 17:28:28 +080096
Lei YUbe5c6b22021-09-16 15:46:20 +080097void initSensorMatches()
98{
99 using namespace sdbusplus::bus::match::rules;
100 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
101 for (const auto& s : ipmi::sensor::sensors)
102 {
103 sensorAddedMatches.emplace(
104 s.first,
105 std::make_unique<sdbusplus::bus::match::match>(
106 bus, interfacesAdded() + argNpath(0, s.second.sensorPath),
107 [id = s.first, obj = s.second.sensorPath](auto& /*msg*/) {
108 // TODO
109 }));
110 sensorUpdatedMatches.emplace(
Lei YU97140502021-09-17 13:49:43 +0800111 s.first, std::make_unique<sdbusplus::bus::match::match>(
112 bus,
113 type::signal() + path(s.second.sensorPath) +
114 member("PropertiesChanged"s) +
115 interface("org.freedesktop.DBus.Properties"s),
116 [&s](auto& msg) {
117 try
118 {
Lei YU8e8152c2021-12-06 20:11:08 +0800119 // This is signal callback
120 std::string interfaceName;
121 msg.read(interfaceName);
122 ipmi::PropertyMap props;
123 msg.read(props);
124 s.second.getFunc(s.first, s.second, props);
Lei YU97140502021-09-17 13:49:43 +0800125 }
126 catch (const std::exception& e)
127 {
128 sensorCacheMap[s.first].reset();
129 }
130 }));
Lei YUbe5c6b22021-09-16 15:46:20 +0800131 }
132}
Lei YU962e68b2021-09-16 16:25:34 +0800133#endif
Lei YUbe5c6b22021-09-16 15:46:20 +0800134
Patrick Venture0b02be92018-08-31 11:55:55 -0700135int get_bus_for_path(const char* path, char** busname)
136{
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700137 return mapper_get_service(bus, path, busname);
138}
Tomd700e762016-09-20 18:24:13 +0530139
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700140// Use a lookup table to find the interface name of a specific sensor
141// This will be used until an alternative is found. this is the first
142// step for mapping IPMI
Patrick Venture0b02be92018-08-31 11:55:55 -0700143int find_openbmc_path(uint8_t num, dbus_interface_t* interface)
144{
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700145 int rc;
146
Patrick Venturedb0cbe62019-09-09 14:47:22 -0700147 const auto& sensor_it = ipmi::sensor::sensors.find(num);
148 if (sensor_it == ipmi::sensor::sensors.end())
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700149 {
Adriana Kobylakba23ff72018-09-12 12:58:43 -0500150 // The sensor map does not contain the sensor requested
151 return -EINVAL;
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700152 }
153
154 const auto& info = sensor_it->second;
155
Patrick Williams8451edf2017-06-13 09:01:06 -0500156 char* busname = nullptr;
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700157 rc = get_bus_for_path(info.sensorPath.c_str(), &busname);
Patrick Venture0b02be92018-08-31 11:55:55 -0700158 if (rc < 0)
159 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700160 std::fprintf(stderr, "Failed to get %s busname: %s\n",
161 info.sensorPath.c_str(), busname);
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700162 goto final;
163 }
164
165 interface->sensortype = info.sensorType;
166 strcpy(interface->bus, busname);
167 strcpy(interface->path, info.sensorPath.c_str());
168 // Take the interface name from the beginning of the DbusInterfaceMap. This
169 // works for the Value interface but may not suffice for more complex
170 // sensors.
171 // tracked https://github.com/openbmc/phosphor-host-ipmid/issues/103
Patrick Venture0b02be92018-08-31 11:55:55 -0700172 strcpy(interface->interface,
173 info.propertyInterfaces.begin()->first.c_str());
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700174 interface->sensornumber = num;
175
176final:
177 free(busname);
178 return rc;
179}
180
Tomd700e762016-09-20 18:24:13 +0530181/////////////////////////////////////////////////////////////////////
182//
183// Routines used by ipmi commands wanting to interact on the dbus
184//
185/////////////////////////////////////////////////////////////////////
Patrick Venture0b02be92018-08-31 11:55:55 -0700186int set_sensor_dbus_state_s(uint8_t number, const char* method,
187 const char* value)
188{
Tomd700e762016-09-20 18:24:13 +0530189
190 dbus_interface_t a;
191 int r;
192 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700193 sd_bus_message* m = NULL;
Tomd700e762016-09-20 18:24:13 +0530194
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700195 r = find_openbmc_path(number, &a);
Tomd700e762016-09-20 18:24:13 +0530196
Patrick Venture0b02be92018-08-31 11:55:55 -0700197 if (r < 0)
198 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700199 std::fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
Tomd700e762016-09-20 18:24:13 +0530200 return 0;
201 }
202
Patrick Venture0b02be92018-08-31 11:55:55 -0700203 r = sd_bus_message_new_method_call(bus, &m, a.bus, a.path, a.interface,
204 method);
205 if (r < 0)
206 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700207 std::fprintf(stderr, "Failed to create a method call: %s",
208 strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530209 goto final;
210 }
211
212 r = sd_bus_message_append(m, "v", "s", value);
Patrick Venture0b02be92018-08-31 11:55:55 -0700213 if (r < 0)
214 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700215 std::fprintf(stderr, "Failed to create a input parameter: %s",
216 strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530217 goto final;
218 }
219
Tomd700e762016-09-20 18:24:13 +0530220 r = sd_bus_call(bus, m, 0, &error, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700221 if (r < 0)
222 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700223 std::fprintf(stderr, "Failed to call the method: %s", strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530224 }
225
226final:
227 sd_bus_error_free(&error);
228 m = sd_bus_message_unref(m);
229
230 return 0;
231}
Patrick Venture0b02be92018-08-31 11:55:55 -0700232int set_sensor_dbus_state_y(uint8_t number, const char* method,
233 const uint8_t value)
234{
Tomd700e762016-09-20 18:24:13 +0530235
236 dbus_interface_t a;
237 int r;
238 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700239 sd_bus_message* m = NULL;
Tomd700e762016-09-20 18:24:13 +0530240
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700241 r = find_openbmc_path(number, &a);
Tomd700e762016-09-20 18:24:13 +0530242
Patrick Venture0b02be92018-08-31 11:55:55 -0700243 if (r < 0)
244 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700245 std::fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
Tomd700e762016-09-20 18:24:13 +0530246 return 0;
247 }
248
Patrick Venture0b02be92018-08-31 11:55:55 -0700249 r = sd_bus_message_new_method_call(bus, &m, a.bus, a.path, a.interface,
250 method);
251 if (r < 0)
252 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700253 std::fprintf(stderr, "Failed to create a method call: %s",
254 strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530255 goto final;
256 }
257
258 r = sd_bus_message_append(m, "v", "i", value);
Patrick Venture0b02be92018-08-31 11:55:55 -0700259 if (r < 0)
260 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700261 std::fprintf(stderr, "Failed to create a input parameter: %s",
262 strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530263 goto final;
264 }
265
Tomd700e762016-09-20 18:24:13 +0530266 r = sd_bus_call(bus, m, 0, &error, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700267 if (r < 0)
268 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700269 std::fprintf(stderr, "12 Failed to call the method: %s", strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530270 }
271
272final:
273 sd_bus_error_free(&error);
274 m = sd_bus_message_unref(m);
275
276 return 0;
277}
278
Patrick Venture0b02be92018-08-31 11:55:55 -0700279uint8_t dbus_to_sensor_type(char* p)
280{
Chris Austenac4604a2015-10-13 12:43:27 -0500281
Patrick Venture0b02be92018-08-31 11:55:55 -0700282 sensorTypemap_t* s = g_SensorTypeMap;
283 char r = 0;
284 while (s->number != 0xFF)
285 {
286 if (!strcmp(s->dbusname, p))
287 {
Tom Joseph558184e2017-09-01 13:45:05 +0530288 r = s->typecode;
Patrick Venture0b02be92018-08-31 11:55:55 -0700289 break;
Chris Austenac4604a2015-10-13 12:43:27 -0500290 }
Chris Austen0012e9b2015-10-22 01:37:46 -0500291 s++;
Chris Austenac4604a2015-10-13 12:43:27 -0500292 }
293
Chris Austen0012e9b2015-10-22 01:37:46 -0500294 if (s->number == 0xFF)
295 printf("Failed to find Sensor Type %s\n", p);
Chris Austenac4604a2015-10-13 12:43:27 -0500296
Chris Austen0012e9b2015-10-22 01:37:46 -0500297 return r;
Chris Austenac4604a2015-10-13 12:43:27 -0500298}
299
Patrick Venture0b02be92018-08-31 11:55:55 -0700300uint8_t get_type_from_interface(dbus_interface_t dbus_if)
301{
Chris Austen0012e9b2015-10-22 01:37:46 -0500302
Brad Bishop56003452016-10-05 21:49:19 -0400303 uint8_t type;
Chris Austen0012e9b2015-10-22 01:37:46 -0500304
Chris Austen0012e9b2015-10-22 01:37:46 -0500305 // This is where sensors that do not exist in dbus but do
306 // exist in the host code stop. This should indicate it
307 // is not a supported sensor
Patrick Venture0b02be92018-08-31 11:55:55 -0700308 if (dbus_if.interface[0] == 0)
309 {
310 return 0;
311 }
Chris Austen0012e9b2015-10-22 01:37:46 -0500312
Emily Shaffer71174412017-04-05 15:10:40 -0700313 // Fetch type from interface itself.
314 if (dbus_if.sensortype != 0)
315 {
316 type = dbus_if.sensortype;
Patrick Venture0b02be92018-08-31 11:55:55 -0700317 }
318 else
319 {
Chris Austen0012e9b2015-10-22 01:37:46 -0500320 // Non InventoryItems
Patrick Venture4491a462018-10-13 13:00:42 -0700321 char* p = strrchr(dbus_if.path, '/');
Patrick Venture0b02be92018-08-31 11:55:55 -0700322 type = dbus_to_sensor_type(p + 1);
Chris Austen0012e9b2015-10-22 01:37:46 -0500323 }
324
Brad Bishop56003452016-10-05 21:49:19 -0400325 return type;
Patrick Venture0b02be92018-08-31 11:55:55 -0700326}
Chris Austen0012e9b2015-10-22 01:37:46 -0500327
Emily Shaffer391f3302017-04-03 10:27:08 -0700328// Replaces find_sensor
Patrick Venture0b02be92018-08-31 11:55:55 -0700329uint8_t find_type_for_sensor_number(uint8_t num)
330{
Emily Shaffer391f3302017-04-03 10:27:08 -0700331 int r;
332 dbus_interface_t dbus_if;
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700333 r = find_openbmc_path(num, &dbus_if);
Patrick Venture0b02be92018-08-31 11:55:55 -0700334 if (r < 0)
335 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700336 std::fprintf(stderr, "Could not find sensor %d\n", num);
Lei YU91875f72018-04-03 15:14:49 +0800337 return 0;
Emily Shaffer391f3302017-04-03 10:27:08 -0700338 }
339 return get_type_from_interface(dbus_if);
340}
341
Deepak Kumar Sahua8be7dc2019-05-07 14:26:53 +0000342/**
343 * @brief implements the get sensor type command.
344 * @param - sensorNumber
345 *
346 * @return IPMI completion code plus response data on success.
347 * - sensorType
348 * - eventType
349 **/
350
351ipmi::RspType<uint8_t, // sensorType
352 uint8_t // eventType
353 >
354 ipmiGetSensorType(uint8_t sensorNumber)
Chris Austenac4604a2015-10-13 12:43:27 -0500355{
Deepak Kumar Sahua8be7dc2019-05-07 14:26:53 +0000356 uint8_t sensorType = find_type_for_sensor_number(sensorNumber);
Chris Austenac4604a2015-10-13 12:43:27 -0500357
Deepak Kumar Sahua8be7dc2019-05-07 14:26:53 +0000358 if (sensorType == 0)
Patrick Venture0b02be92018-08-31 11:55:55 -0700359 {
Deepak Kumar Sahua8be7dc2019-05-07 14:26:53 +0000360 return ipmi::responseSensorInvalid();
Chris Austen0012e9b2015-10-22 01:37:46 -0500361 }
362
Deepak Kumar Sahua8be7dc2019-05-07 14:26:53 +0000363 constexpr uint8_t eventType = 0x6F;
364 return ipmi::responseSuccess(sensorType, eventType);
Chris Austenac4604a2015-10-13 12:43:27 -0500365}
366
Patrick Venture0b02be92018-08-31 11:55:55 -0700367const std::set<std::string> analogSensorInterfaces = {
Emily Shaffercc941e12017-06-14 13:06:26 -0700368 "xyz.openbmc_project.Sensor.Value",
Patrick Venturee9a64052017-08-18 19:17:27 -0700369 "xyz.openbmc_project.Control.FanPwm",
Emily Shaffercc941e12017-06-14 13:06:26 -0700370};
371
372bool isAnalogSensor(const std::string& interface)
373{
374 return (analogSensorInterfaces.count(interface));
375}
376
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000377/**
378@brief This command is used to set sensorReading.
379
380@param
381 - sensorNumber
382 - operation
383 - reading
384 - assertOffset0_7
385 - assertOffset8_14
386 - deassertOffset0_7
387 - deassertOffset8_14
388 - eventData1
389 - eventData2
390 - eventData3
391
392@return completion code on success.
393**/
394
395ipmi::RspType<> ipmiSetSensorReading(uint8_t sensorNumber, uint8_t operation,
396 uint8_t reading, uint8_t assertOffset0_7,
397 uint8_t assertOffset8_14,
398 uint8_t deassertOffset0_7,
399 uint8_t deassertOffset8_14,
400 uint8_t eventData1, uint8_t eventData2,
401 uint8_t eventData3)
Tom Josephbe703f72017-03-09 12:34:35 +0530402{
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000403 log<level::DEBUG>("IPMI SET_SENSOR",
404 entry("SENSOR_NUM=0x%02x", sensorNumber));
405
Arun P. Mohanan0634e982021-08-30 15:21:33 +0530406 if (sensorNumber == 0xFF)
407 {
408 return ipmi::responseInvalidFieldRequest();
409 }
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000410 ipmi::sensor::SetSensorReadingReq cmdData;
411
412 cmdData.number = sensorNumber;
413 cmdData.operation = operation;
414 cmdData.reading = reading;
415 cmdData.assertOffset0_7 = assertOffset0_7;
416 cmdData.assertOffset8_14 = assertOffset8_14;
417 cmdData.deassertOffset0_7 = deassertOffset0_7;
418 cmdData.deassertOffset8_14 = deassertOffset8_14;
419 cmdData.eventData1 = eventData1;
420 cmdData.eventData2 = eventData2;
421 cmdData.eventData3 = eventData3;
Tom Josephbe703f72017-03-09 12:34:35 +0530422
423 // Check if the Sensor Number is present
Patrick Venturedb0cbe62019-09-09 14:47:22 -0700424 const auto iter = ipmi::sensor::sensors.find(sensorNumber);
425 if (iter == ipmi::sensor::sensors.end())
Tom Josephbe703f72017-03-09 12:34:35 +0530426 {
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000427 updateSensorRecordFromSSRAESC(&sensorNumber);
428 return ipmi::responseSuccess();
Tom Josephbe703f72017-03-09 12:34:35 +0530429 }
430
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -0500431 try
432 {
Jayanth Othayoth0922bde2018-04-02 07:59:34 -0500433 if (ipmi::sensor::Mutability::Write !=
Patrick Venture0b02be92018-08-31 11:55:55 -0700434 (iter->second.mutability & ipmi::sensor::Mutability::Write))
Jayanth Othayoth0922bde2018-04-02 07:59:34 -0500435 {
436 log<level::ERR>("Sensor Set operation is not allowed",
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000437 entry("SENSOR_NUM=%d", sensorNumber));
438 return ipmi::responseIllegalCommand();
Jayanth Othayoth0922bde2018-04-02 07:59:34 -0500439 }
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000440 auto ipmiRC = iter->second.updateFunc(cmdData, iter->second);
441 return ipmi::response(ipmiRC);
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -0500442 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500443 catch (const InternalFailure& e)
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -0500444 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700445 log<level::ERR>("Set sensor failed",
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000446 entry("SENSOR_NUM=%d", sensorNumber));
Patrick Venture0b02be92018-08-31 11:55:55 -0700447 commit<InternalFailure>();
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000448 return ipmi::responseUnspecifiedError();
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -0500449 }
Tom Joseph82024322017-09-28 20:07:29 +0530450 catch (const std::runtime_error& e)
451 {
452 log<level::ERR>(e.what());
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +0000453 return ipmi::responseUnspecifiedError();
Tom Joseph82024322017-09-28 20:07:29 +0530454 }
Chris Austenac4604a2015-10-13 12:43:27 -0500455}
456
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000457/** @brief implements the get sensor reading command
458 * @param sensorNum - sensor number
459 *
460 * @returns IPMI completion code plus response data
461 * - senReading - sensor reading
462 * - reserved
463 * - readState - sensor reading state enabled
464 * - senScanState - sensor scan state disabled
465 * - allEventMessageState - all Event message state disabled
466 * - assertionStatesLsb - threshold levels states
467 * - assertionStatesMsb - discrete reading sensor states
468 */
469ipmi::RspType<uint8_t, // sensor reading
Tom Joseph3ee668f2018-03-02 19:49:17 +0530470
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000471 uint5_t, // reserved
472 bool, // reading state
Sui Chen4cc42552019-09-11 10:28:35 -0700473 bool, // 0 = sensor scanning state disabled
474 bool, // 0 = all event messages disabled
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000475
476 uint8_t, // threshold levels states
477 uint8_t // discrete reading sensor states
478 >
Lei YU8e8152c2021-12-06 20:11:08 +0800479 ipmiSensorGetSensorReading(ipmi::Context::ptr& ctx, uint8_t sensorNum)
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000480{
481 if (sensorNum == 0xFF)
482 {
483 return ipmi::responseInvalidFieldRequest();
484 }
485
486 const auto iter = ipmi::sensor::sensors.find(sensorNum);
Patrick Venturedb0cbe62019-09-09 14:47:22 -0700487 if (iter == ipmi::sensor::sensors.end())
Tom Joseph3ee668f2018-03-02 19:49:17 +0530488 {
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000489 return ipmi::responseSensorInvalid();
Tom Joseph3ee668f2018-03-02 19:49:17 +0530490 }
491 if (ipmi::sensor::Mutability::Read !=
Patrick Venture0b02be92018-08-31 11:55:55 -0700492 (iter->second.mutability & ipmi::sensor::Mutability::Read))
Tom Joseph3ee668f2018-03-02 19:49:17 +0530493 {
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000494 return ipmi::responseIllegalCommand();
Tom Joseph3ee668f2018-03-02 19:49:17 +0530495 }
496
497 try
498 {
Lei YU8c2c0482021-09-16 17:28:28 +0800499#ifdef FEATURE_SENSORS_CACHE
Lei YU8e8152c2021-12-06 20:11:08 +0800500 auto& sensorData = sensorCacheMap[sensorNum];
Lei YU97140502021-09-17 13:49:43 +0800501 if (!sensorData.has_value())
502 {
Lei YUa55e9ea2021-09-18 15:15:17 +0800503 // No cached value, try read it
Lei YU8e8152c2021-12-06 20:11:08 +0800504 std::string service;
505 boost::system::error_code ec;
Lei YUa55e9ea2021-09-18 15:15:17 +0800506 const auto& sensorInfo = iter->second;
Lei YU8e8152c2021-12-06 20:11:08 +0800507 ec = ipmi::getService(ctx, sensorInfo.sensorInterface,
508 sensorInfo.sensorPath, service);
509 if (ec)
Lei YUa55e9ea2021-09-18 15:15:17 +0800510 {
Lei YU8e8152c2021-12-06 20:11:08 +0800511 return ipmi::responseUnspecifiedError();
Lei YUa55e9ea2021-09-18 15:15:17 +0800512 }
Lei YU8e8152c2021-12-06 20:11:08 +0800513
514 ipmi::PropertyMap props;
515 ec = ipmi::getAllDbusProperties(
516 ctx, service, sensorInfo.sensorPath,
517 sensorInfo.propertyInterfaces.begin()->first, props);
518 if (ec)
Lei YUa55e9ea2021-09-18 15:15:17 +0800519 {
Lei YU8e8152c2021-12-06 20:11:08 +0800520 fprintf(stderr, "Failed to get sensor %s, %d: %s\n",
521 sensorInfo.sensorPath.c_str(), ec.value(),
522 ec.message().c_str());
Lei YUa55e9ea2021-09-18 15:15:17 +0800523 // Intitilizing with default values
524 constexpr uint8_t senReading = 0;
525 constexpr uint5_t reserved{0};
526 constexpr bool readState = true;
527 constexpr bool senScanState = false;
528 constexpr bool allEventMessageState = false;
529 constexpr uint8_t assertionStatesLsb = 0;
530 constexpr uint8_t assertionStatesMsb = 0;
Lei YU97140502021-09-17 13:49:43 +0800531
Lei YUa55e9ea2021-09-18 15:15:17 +0800532 return ipmi::responseSuccess(senReading, reserved, readState,
533 senScanState, allEventMessageState,
534 assertionStatesLsb,
535 assertionStatesMsb);
536 }
Lei YU8e8152c2021-12-06 20:11:08 +0800537 sensorInfo.getFunc(sensorNum, sensorInfo, props);
Lei YU97140502021-09-17 13:49:43 +0800538 }
539 return ipmi::responseSuccess(
540 sensorData->response.reading, uint5_t(0),
541 sensorData->response.readingOrStateUnavailable,
542 sensorData->response.scanningEnabled,
543 sensorData->response.allEventMessagesEnabled,
544 sensorData->response.thresholdLevelsStates,
545 sensorData->response.discreteReadingSensorStates);
546
Lei YU8c2c0482021-09-16 17:28:28 +0800547#else
Sui Chen4cc42552019-09-11 10:28:35 -0700548 ipmi::sensor::GetSensorResponse getResponse =
549 iter->second.getFunc(iter->second);
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000550
Sui Chen4cc42552019-09-11 10:28:35 -0700551 return ipmi::responseSuccess(getResponse.reading, uint5_t(0),
552 getResponse.readingOrStateUnavailable,
553 getResponse.scanningEnabled,
554 getResponse.allEventMessagesEnabled,
555 getResponse.thresholdLevelsStates,
556 getResponse.discreteReadingSensorStates);
Lei YU8c2c0482021-09-16 17:28:28 +0800557#endif
Tom Joseph3ee668f2018-03-02 19:49:17 +0530558 }
Brandon Kim9cf85622019-06-19 12:05:08 -0700559#ifdef UPDATE_FUNCTIONAL_ON_FAIL
560 catch (const SensorFunctionalError& e)
561 {
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000562 return ipmi::responseResponseError();
Brandon Kim9cf85622019-06-19 12:05:08 -0700563 }
564#endif
Tom Joseph3ee668f2018-03-02 19:49:17 +0530565 catch (const std::exception& e)
566 {
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +0000567 // Intitilizing with default values
568 constexpr uint8_t senReading = 0;
569 constexpr uint5_t reserved{0};
570 constexpr bool readState = true;
571 constexpr bool senScanState = false;
572 constexpr bool allEventMessageState = false;
573 constexpr uint8_t assertionStatesLsb = 0;
574 constexpr uint8_t assertionStatesMsb = 0;
575
576 return ipmi::responseSuccess(senReading, reserved, readState,
577 senScanState, allEventMessageState,
578 assertionStatesLsb, assertionStatesMsb);
Tom Joseph3ee668f2018-03-02 19:49:17 +0530579 }
580}
581
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300582get_sdr::GetSensorThresholdsResponse
583 getSensorThresholds(ipmi::Context::ptr& ctx, uint8_t sensorNum)
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600584{
William A. Kennington III515bc372020-10-27 16:32:32 -0700585 get_sdr::GetSensorThresholdsResponse resp{};
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530586 constexpr auto warningThreshIntf =
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600587 "xyz.openbmc_project.Sensor.Threshold.Warning";
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530588 constexpr auto criticalThreshIntf =
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600589 "xyz.openbmc_project.Sensor.Threshold.Critical";
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600590
Patrick Venturedb0cbe62019-09-09 14:47:22 -0700591 const auto iter = ipmi::sensor::sensors.find(sensorNum);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530592 const auto info = iter->second;
593
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300594 std::string service;
595 boost::system::error_code ec;
596 ec = ipmi::getService(ctx, info.sensorInterface, info.sensorPath, service);
597 if (ec)
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530598 {
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300599 return resp;
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530600 }
601
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300602 ipmi::PropertyMap warnThresholds;
603 ec = ipmi::getAllDbusProperties(ctx, service, info.sensorPath,
604 warningThreshIntf, warnThresholds);
605 if (!ec)
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530606 {
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300607 double warnLow = std::visit(ipmi::VariantToDoubleVisitor(),
608 warnThresholds["WarningLow"]);
609 double warnHigh = std::visit(ipmi::VariantToDoubleVisitor(),
610 warnThresholds["WarningHigh"]);
611
612 if (std::isfinite(warnLow))
613 {
614 warnLow *= std::pow(10, info.scale - info.exponentR);
615 resp.lowerNonCritical = static_cast<uint8_t>(
616 (warnLow - info.scaledOffset) / info.coefficientM);
617 resp.validMask |= static_cast<uint8_t>(
618 ipmi::sensor::ThresholdMask::NON_CRITICAL_LOW_MASK);
619 }
620
621 if (std::isfinite(warnHigh))
622 {
623 warnHigh *= std::pow(10, info.scale - info.exponentR);
624 resp.upperNonCritical = static_cast<uint8_t>(
625 (warnHigh - info.scaledOffset) / info.coefficientM);
626 resp.validMask |= static_cast<uint8_t>(
627 ipmi::sensor::ThresholdMask::NON_CRITICAL_HIGH_MASK);
628 }
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530629 }
630
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300631 ipmi::PropertyMap critThresholds;
632 ec = ipmi::getAllDbusProperties(ctx, service, info.sensorPath,
633 criticalThreshIntf, critThresholds);
634 if (!ec)
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530635 {
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300636 double critLow = std::visit(ipmi::VariantToDoubleVisitor(),
637 critThresholds["CriticalLow"]);
638 double critHigh = std::visit(ipmi::VariantToDoubleVisitor(),
639 critThresholds["CriticalHigh"]);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530640
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300641 if (std::isfinite(critLow))
642 {
643 critLow *= std::pow(10, info.scale - info.exponentR);
644 resp.lowerCritical = static_cast<uint8_t>(
645 (critLow - info.scaledOffset) / info.coefficientM);
646 resp.validMask |= static_cast<uint8_t>(
647 ipmi::sensor::ThresholdMask::CRITICAL_LOW_MASK);
648 }
649
650 if (std::isfinite(critHigh))
651 {
652 critHigh *= std::pow(10, info.scale - info.exponentR);
653 resp.upperCritical = static_cast<uint8_t>(
654 (critHigh - info.scaledOffset) / info.coefficientM);
655 resp.validMask |= static_cast<uint8_t>(
656 ipmi::sensor::ThresholdMask::CRITICAL_HIGH_MASK);
657 }
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530658 }
jayaprakash Mutyala996c9792019-05-03 15:56:48 +0000659
660 return resp;
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530661}
662
jayaprakash Mutyala996c9792019-05-03 15:56:48 +0000663/** @brief implements the get sensor thresholds command
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300664 * @param ctx - IPMI context pointer
jayaprakash Mutyala996c9792019-05-03 15:56:48 +0000665 * @param sensorNum - sensor number
666 *
667 * @returns IPMI completion code plus response data
668 * - validMask - threshold mask
669 * - lower non-critical threshold - IPMI messaging state
670 * - lower critical threshold - link authentication state
671 * - lower non-recoverable threshold - callback state
672 * - upper non-critical threshold
673 * - upper critical
674 * - upper non-recoverable
675 */
676ipmi::RspType<uint8_t, // validMask
677 uint8_t, // lowerNonCritical
678 uint8_t, // lowerCritical
679 uint8_t, // lowerNonRecoverable
680 uint8_t, // upperNonCritical
681 uint8_t, // upperCritical
682 uint8_t // upperNonRecoverable
683 >
Konstantin Aladyshev89a83b62021-05-12 18:59:27 +0300684 ipmiSensorGetSensorThresholds(ipmi::Context::ptr& ctx, uint8_t sensorNum)
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530685{
686 constexpr auto valueInterface = "xyz.openbmc_project.Sensor.Value";
687
Patrick Venturedb0cbe62019-09-09 14:47:22 -0700688 const auto iter = ipmi::sensor::sensors.find(sensorNum);
689 if (iter == ipmi::sensor::sensors.end())
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600690 {
jayaprakash Mutyala996c9792019-05-03 15:56:48 +0000691 return ipmi::responseSensorInvalid();
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600692 }
693
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530694 const auto info = iter->second;
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600695
Patrick Venture0b02be92018-08-31 11:55:55 -0700696 // Proceed only if the sensor value interface is implemented.
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530697 if (info.propertyInterfaces.find(valueInterface) ==
698 info.propertyInterfaces.end())
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600699 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700700 // return with valid mask as 0
jayaprakash Mutyala996c9792019-05-03 15:56:48 +0000701 return ipmi::responseSuccess();
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600702 }
703
Lei YU14a47812021-09-17 15:58:04 +0800704 auto it = sensorThresholdMap.find(sensorNum);
705 if (it == sensorThresholdMap.end())
706 {
707 sensorThresholdMap[sensorNum] = getSensorThresholds(ctx, sensorNum);
708 }
709
710 const auto& resp = sensorThresholdMap[sensorNum];
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600711
jayaprakash Mutyala996c9792019-05-03 15:56:48 +0000712 return ipmi::responseSuccess(resp.validMask, resp.lowerNonCritical,
713 resp.lowerCritical, resp.lowerNonRecoverable,
714 resp.upperNonCritical, resp.upperCritical,
715 resp.upperNonRecoverable);
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600716}
717
Lotus Xuf93da662021-10-18 17:20:06 +0800718/** @brief implements the Set Sensor threshold command
719 * @param sensorNumber - sensor number
720 * @param lowerNonCriticalThreshMask
721 * @param lowerCriticalThreshMask
722 * @param lowerNonRecovThreshMask
723 * @param upperNonCriticalThreshMask
724 * @param upperCriticalThreshMask
725 * @param upperNonRecovThreshMask
726 * @param reserved
727 * @param lowerNonCritical - lower non-critical threshold
728 * @param lowerCritical - Lower critical threshold
729 * @param lowerNonRecoverable - Lower non recovarable threshold
730 * @param upperNonCritical - Upper non-critical threshold
731 * @param upperCritical - Upper critical
732 * @param upperNonRecoverable - Upper Non-recoverable
733 *
734 * @returns IPMI completion code
735 */
736ipmi::RspType<> ipmiSenSetSensorThresholds(
737 ipmi::Context::ptr& ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
738 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
739 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
740 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
741 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
742 uint8_t upperNonCritical, uint8_t upperCritical,
743 uint8_t upperNonRecoverable)
744{
745 if (reserved)
746 {
747 return ipmi::responseInvalidFieldRequest();
748 }
749
750 // lower nc and upper nc not suppported on any sensor
751 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
752 {
753 return ipmi::responseInvalidFieldRequest();
754 }
755
756 // if none of the threshold mask are set, nothing to do
757 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
758 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
759 upperCriticalThreshMask | upperNonRecovThreshMask))
760 {
761 return ipmi::responseSuccess();
762 }
763
764 constexpr auto valueInterface = "xyz.openbmc_project.Sensor.Value";
765
766 const auto iter = ipmi::sensor::sensors.find(sensorNum);
767 if (iter == ipmi::sensor::sensors.end())
768 {
769 return ipmi::responseSensorInvalid();
770 }
771
772 const auto& info = iter->second;
773
774 // Proceed only if the sensor value interface is implemented.
775 if (info.propertyInterfaces.find(valueInterface) ==
776 info.propertyInterfaces.end())
777 {
778 // return with valid mask as 0
779 return ipmi::responseSuccess();
780 }
781
782 constexpr auto warningThreshIntf =
783 "xyz.openbmc_project.Sensor.Threshold.Warning";
784 constexpr auto criticalThreshIntf =
785 "xyz.openbmc_project.Sensor.Threshold.Critical";
786
787 std::string service;
788 boost::system::error_code ec;
789 ec = ipmi::getService(ctx, info.sensorInterface, info.sensorPath, service);
790 if (ec)
791 {
792 return ipmi::responseResponseError();
793 }
794 // store a vector of property name, value to set, and interface
795 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
796
797 // define the indexes of the tuple
798 constexpr uint8_t propertyName = 0;
799 constexpr uint8_t thresholdValue = 1;
800 constexpr uint8_t interface = 2;
801 // verifiy all needed fields are present
802 if (lowerCriticalThreshMask || upperCriticalThreshMask)
803 {
804
805 ipmi::PropertyMap findThreshold;
806 ec = ipmi::getAllDbusProperties(ctx, service, info.sensorPath,
807 criticalThreshIntf, findThreshold);
808
809 if (!ec)
810 {
811 if (lowerCriticalThreshMask)
812 {
813 auto findLower = findThreshold.find("CriticalLow");
814 if (findLower == findThreshold.end())
815 {
816 return ipmi::responseInvalidFieldRequest();
817 }
818 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
819 criticalThreshIntf);
820 }
821 if (upperCriticalThreshMask)
822 {
823 auto findUpper = findThreshold.find("CriticalHigh");
824 if (findUpper == findThreshold.end())
825 {
826 return ipmi::responseInvalidFieldRequest();
827 }
828 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
829 criticalThreshIntf);
830 }
831 }
832 }
833 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
834 {
835 ipmi::PropertyMap findThreshold;
836 ec = ipmi::getAllDbusProperties(ctx, service, info.sensorPath,
837 warningThreshIntf, findThreshold);
838
839 if (!ec)
840 {
841 if (lowerNonCriticalThreshMask)
842 {
843 auto findLower = findThreshold.find("WarningLow");
844 if (findLower == findThreshold.end())
845 {
846 return ipmi::responseInvalidFieldRequest();
847 }
848 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
849 warningThreshIntf);
850 }
851 if (upperNonCriticalThreshMask)
852 {
853 auto findUpper = findThreshold.find("WarningHigh");
854 if (findUpper == findThreshold.end())
855 {
856 return ipmi::responseInvalidFieldRequest();
857 }
858 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
859 warningThreshIntf);
860 }
861 }
862 }
863 for (const auto& property : thresholdsToSet)
864 {
865 // from section 36.3 in the IPMI Spec, assume all linear
866 double valueToSet =
867 ((info.coefficientM * std::get<thresholdValue>(property)) +
868 (info.scaledOffset * std::pow(10.0, info.scale))) *
869 std::pow(10.0, info.exponentR);
870 ipmi::setDbusProperty(
871 ctx, service, info.sensorPath, std::get<interface>(property),
872 std::get<propertyName>(property), ipmi::Value(valueToSet));
873 }
874
Lei YU14a47812021-09-17 15:58:04 +0800875 // Invalidate the cache
876 sensorThresholdMap.erase(sensorNum);
Lotus Xuf93da662021-10-18 17:20:06 +0800877 return ipmi::responseSuccess();
878}
879
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000880/** @brief implements the get SDR Info command
881 * @param count - Operation
882 *
883 * @returns IPMI completion code plus response data
884 * - sdrCount - sensor/SDR count
885 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
886 */
887ipmi::RspType<uint8_t, // respcount
888 uint8_t // dynamic population flags
889 >
890 ipmiSensorGetDeviceSdrInfo(std::optional<uint8_t> count)
Emily Shafferd06e0e72017-04-05 09:08:57 -0700891{
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000892 uint8_t sdrCount;
893 // multiple LUNs not supported.
894 constexpr uint8_t lunsAndDynamicPopulation = 1;
895 constexpr uint8_t getSdrCount = 0x01;
896 constexpr uint8_t getSensorCount = 0x00;
897
898 if (count.value_or(0) == getSdrCount)
Emily Shafferd06e0e72017-04-05 09:08:57 -0700899 {
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000900 // Get SDR count. This returns the total number of SDRs in the device.
Patrick Venture87fd2cd2019-08-19 12:07:18 -0700901 const auto& entityRecords =
902 ipmi::sensor::EntityInfoMapContainer::getContainer()
903 ->getIpmiEntityRecords();
Patrick Venturedb0cbe62019-09-09 14:47:22 -0700904 sdrCount =
905 ipmi::sensor::sensors.size() + frus.size() + entityRecords.size();
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000906 }
907 else if (count.value_or(0) == getSensorCount)
908 {
909 // Get Sensor count. This returns the number of sensors
Patrick Venturedb0cbe62019-09-09 14:47:22 -0700910 sdrCount = ipmi::sensor::sensors.size();
Emily Shafferd06e0e72017-04-05 09:08:57 -0700911 }
912 else
913 {
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000914 return ipmi::responseInvalidCommandOnLun();
Emily Shafferd06e0e72017-04-05 09:08:57 -0700915 }
916
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000917 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation);
Emily Shafferd06e0e72017-04-05 09:08:57 -0700918}
919
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000920/** @brief implements the reserve SDR command
921 * @returns IPMI completion code plus response data
922 * - reservationID - reservation ID
923 */
924ipmi::RspType<uint16_t> ipmiSensorReserveSdr()
Emily Shaffera344afc2017-04-13 15:09:39 -0700925{
926 // A constant reservation ID is okay until we implement add/remove SDR.
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000927 constexpr uint16_t reservationID = 1;
Emily Shaffera344afc2017-04-13 15:09:39 -0700928
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000929 return ipmi::responseSuccess(reservationID);
Emily Shaffera344afc2017-04-13 15:09:39 -0700930}
Chris Austenac4604a2015-10-13 12:43:27 -0500931
Patrick Venture0b02be92018-08-31 11:55:55 -0700932void setUnitFieldsForObject(const ipmi::sensor::Info* info,
933 get_sdr::SensorDataFullRecordBody* body)
Emily Shaffercc941e12017-06-14 13:06:26 -0700934{
Tom Josephdc212b22018-02-16 09:59:57 +0530935 namespace server = sdbusplus::xyz::openbmc_project::Sensor::server;
936 try
Emily Shaffercc941e12017-06-14 13:06:26 -0700937 {
Tom Josephdc212b22018-02-16 09:59:57 +0530938 auto unit = server::Value::convertUnitFromString(info->unit);
939 // Unit strings defined in
940 // phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Value.interface.yaml
941 switch (unit)
Emily Shaffercc941e12017-06-14 13:06:26 -0700942 {
Tom Josephdc212b22018-02-16 09:59:57 +0530943 case server::Value::Unit::DegreesC:
944 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_DEGREES_C;
945 break;
946 case server::Value::Unit::RPMS:
Kirill Pakhomov812e44c2018-10-22 16:25:35 +0300947 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_RPM;
Tom Josephdc212b22018-02-16 09:59:57 +0530948 break;
949 case server::Value::Unit::Volts:
950 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_VOLTS;
951 break;
952 case server::Value::Unit::Meters:
953 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_METERS;
954 break;
955 case server::Value::Unit::Amperes:
956 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_AMPERES;
957 break;
958 case server::Value::Unit::Joules:
959 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_JOULES;
960 break;
961 case server::Value::Unit::Watts:
962 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_WATTS;
963 break;
964 default:
965 // Cannot be hit.
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700966 std::fprintf(stderr, "Unknown value unit type: = %s\n",
967 info->unit.c_str());
Emily Shaffercc941e12017-06-14 13:06:26 -0700968 }
969 }
Patrick Venture64678b82018-10-13 13:11:32 -0700970 catch (const sdbusplus::exception::InvalidEnumString& e)
Emily Shaffercc941e12017-06-14 13:06:26 -0700971 {
Tom Josephdc212b22018-02-16 09:59:57 +0530972 log<level::WARNING>("Warning: no unit provided for sensor!");
Emily Shaffercc941e12017-06-14 13:06:26 -0700973 }
Emily Shaffercc941e12017-06-14 13:06:26 -0700974}
975
Patrick Venture0b02be92018-08-31 11:55:55 -0700976ipmi_ret_t populate_record_from_dbus(get_sdr::SensorDataFullRecordBody* body,
977 const ipmi::sensor::Info* info,
Emily Shafferbbef71c2017-05-08 16:36:17 -0700978 ipmi_data_len_t data_len)
979{
980 /* Functional sensor case */
Emily Shaffercc941e12017-06-14 13:06:26 -0700981 if (isAnalogSensor(info->propertyInterfaces.begin()->first))
Emily Shafferbbef71c2017-05-08 16:36:17 -0700982 {
Tony Leec5324252019-10-31 17:24:16 +0800983 body->sensor_units_1 = info->sensorUnits1; // default is 0. unsigned, no
984 // rate, no modifier, not a %
Emily Shafferbbef71c2017-05-08 16:36:17 -0700985 /* Unit info */
Tom Josephdc212b22018-02-16 09:59:57 +0530986 setUnitFieldsForObject(info, body);
Emily Shaffer10f49592017-05-10 12:01:10 -0700987
988 get_sdr::body::set_b(info->coefficientB, body);
989 get_sdr::body::set_m(info->coefficientM, body);
990 get_sdr::body::set_b_exp(info->exponentB, body);
Tom Josephdc212b22018-02-16 09:59:57 +0530991 get_sdr::body::set_r_exp(info->exponentR, body);
Emily Shafferbbef71c2017-05-08 16:36:17 -0700992
Emily Shafferbbef71c2017-05-08 16:36:17 -0700993 get_sdr::body::set_id_type(0b00, body); // 00 = unicode
Emily Shafferbbef71c2017-05-08 16:36:17 -0700994 }
995
Tom Joseph96423912018-01-25 00:14:34 +0530996 /* ID string */
Jeremy Kerrbe4ffa82020-08-10 16:17:37 +0800997 auto id_string = info->sensorName;
998
999 if (id_string.empty())
1000 {
1001 id_string = info->sensorNameFunc(*info);
1002 }
Tom Joseph96423912018-01-25 00:14:34 +05301003
1004 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
1005 {
1006 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH, body);
1007 }
1008 else
1009 {
1010 get_sdr::body::set_id_strlen(id_string.length(), body);
1011 }
1012 strncpy(body->id_string, id_string.c_str(),
1013 get_sdr::body::get_id_strlen(body));
1014
Emily Shafferbbef71c2017-05-08 16:36:17 -07001015 return IPMI_CC_OK;
1016};
1017
Ratan Guptae0cc8552018-01-22 14:23:04 +05301018ipmi_ret_t ipmi_fru_get_sdr(ipmi_request_t request, ipmi_response_t response,
1019 ipmi_data_len_t data_len)
1020{
1021 auto req = reinterpret_cast<get_sdr::GetSdrReq*>(request);
1022 auto resp = reinterpret_cast<get_sdr::GetSdrResp*>(response);
Patrick Venture0b02be92018-08-31 11:55:55 -07001023 get_sdr::SensorDataFruRecord record{};
Ratan Guptae0cc8552018-01-22 14:23:04 +05301024 auto dataLength = 0;
1025
1026 auto fru = frus.begin();
Patrick Venture0b02be92018-08-31 11:55:55 -07001027 uint8_t fruID{};
Ratan Guptae0cc8552018-01-22 14:23:04 +05301028 auto recordID = get_sdr::request::get_record_id(req);
1029
1030 fruID = recordID - FRU_RECORD_ID_START;
1031 fru = frus.find(fruID);
1032 if (fru == frus.end())
1033 {
1034 return IPMI_CC_SENSOR_INVALID;
1035 }
1036
1037 /* Header */
1038 get_sdr::header::set_record_id(recordID, &(record.header));
1039 record.header.sdr_version = SDR_VERSION; // Based on IPMI Spec v2.0 rev 1.1
1040 record.header.record_type = get_sdr::SENSOR_DATA_FRU_RECORD;
1041 record.header.record_length = sizeof(record.key) + sizeof(record.body);
1042
1043 /* Key */
1044 record.key.fruID = fruID;
1045 record.key.accessLun |= IPMI_LOGICAL_FRU;
1046 record.key.deviceAddress = BMCSlaveAddress;
1047
1048 /* Body */
1049 record.body.entityID = fru->second[0].entityID;
1050 record.body.entityInstance = fru->second[0].entityInstance;
1051 record.body.deviceType = fruInventoryDevice;
1052 record.body.deviceTypeModifier = IPMIFruInventory;
1053
1054 /* Device ID string */
Patrick Venture0b02be92018-08-31 11:55:55 -07001055 auto deviceID =
1056 fru->second[0].path.substr(fru->second[0].path.find_last_of('/') + 1,
1057 fru->second[0].path.length());
Ratan Guptae0cc8552018-01-22 14:23:04 +05301058
1059 if (deviceID.length() > get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH)
1060 {
1061 get_sdr::body::set_device_id_strlen(
Patrick Venture0b02be92018-08-31 11:55:55 -07001062 get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH, &(record.body));
Ratan Guptae0cc8552018-01-22 14:23:04 +05301063 }
1064 else
1065 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001066 get_sdr::body::set_device_id_strlen(deviceID.length(), &(record.body));
Ratan Guptae0cc8552018-01-22 14:23:04 +05301067 }
1068
1069 strncpy(record.body.deviceID, deviceID.c_str(),
1070 get_sdr::body::get_device_id_strlen(&(record.body)));
1071
1072 if (++fru == frus.end())
1073 {
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -08001074 // we have reached till end of fru, so assign the next record id to
1075 // 512(Max fru ID = 511) + Entity Record ID(may start with 0).
Patrick Venture87fd2cd2019-08-19 12:07:18 -07001076 const auto& entityRecords =
1077 ipmi::sensor::EntityInfoMapContainer::getContainer()
1078 ->getIpmiEntityRecords();
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -08001079 auto next_record_id =
Patrick Venture83a0b842019-07-19 18:37:15 -07001080 (entityRecords.size())
1081 ? entityRecords.begin()->first + ENTITY_RECORD_ID_START
1082 : END_OF_RECORD;
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -08001083 get_sdr::response::set_next_record_id(next_record_id, resp);
1084 }
1085 else
1086 {
1087 get_sdr::response::set_next_record_id(
1088 (FRU_RECORD_ID_START + fru->first), resp);
1089 }
1090
1091 // Check for invalid offset size
1092 if (req->offset > sizeof(record))
1093 {
1094 return IPMI_CC_PARM_OUT_OF_RANGE;
1095 }
1096
1097 dataLength = std::min(static_cast<size_t>(req->bytes_to_read),
1098 sizeof(record) - req->offset);
1099
1100 std::memcpy(resp->record_data,
1101 reinterpret_cast<uint8_t*>(&record) + req->offset, dataLength);
1102
1103 *data_len = dataLength;
1104 *data_len += 2; // additional 2 bytes for next record ID
1105
1106 return IPMI_CC_OK;
1107}
1108
1109ipmi_ret_t ipmi_entity_get_sdr(ipmi_request_t request, ipmi_response_t response,
1110 ipmi_data_len_t data_len)
1111{
1112 auto req = reinterpret_cast<get_sdr::GetSdrReq*>(request);
1113 auto resp = reinterpret_cast<get_sdr::GetSdrResp*>(response);
1114 get_sdr::SensorDataEntityRecord record{};
1115 auto dataLength = 0;
1116
Patrick Venture87fd2cd2019-08-19 12:07:18 -07001117 const auto& entityRecords =
1118 ipmi::sensor::EntityInfoMapContainer::getContainer()
1119 ->getIpmiEntityRecords();
Patrick Venture83a0b842019-07-19 18:37:15 -07001120 auto entity = entityRecords.begin();
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -08001121 uint8_t entityRecordID;
1122 auto recordID = get_sdr::request::get_record_id(req);
1123
1124 entityRecordID = recordID - ENTITY_RECORD_ID_START;
Patrick Venture83a0b842019-07-19 18:37:15 -07001125 entity = entityRecords.find(entityRecordID);
1126 if (entity == entityRecords.end())
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -08001127 {
1128 return IPMI_CC_SENSOR_INVALID;
1129 }
1130
1131 /* Header */
1132 get_sdr::header::set_record_id(recordID, &(record.header));
1133 record.header.sdr_version = SDR_VERSION; // Based on IPMI Spec v2.0 rev 1.1
1134 record.header.record_type = get_sdr::SENSOR_DATA_ENTITY_RECORD;
1135 record.header.record_length = sizeof(record.key) + sizeof(record.body);
1136
1137 /* Key */
1138 record.key.containerEntityId = entity->second.containerEntityId;
1139 record.key.containerEntityInstance = entity->second.containerEntityInstance;
1140 get_sdr::key::set_flags(entity->second.isList, entity->second.isLinked,
1141 &(record.key));
1142 record.key.entityId1 = entity->second.containedEntities[0].first;
1143 record.key.entityInstance1 = entity->second.containedEntities[0].second;
1144
1145 /* Body */
1146 record.body.entityId2 = entity->second.containedEntities[1].first;
1147 record.body.entityInstance2 = entity->second.containedEntities[1].second;
1148 record.body.entityId3 = entity->second.containedEntities[2].first;
1149 record.body.entityInstance3 = entity->second.containedEntities[2].second;
1150 record.body.entityId4 = entity->second.containedEntities[3].first;
1151 record.body.entityInstance4 = entity->second.containedEntities[3].second;
1152
Patrick Venture83a0b842019-07-19 18:37:15 -07001153 if (++entity == entityRecords.end())
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -08001154 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001155 get_sdr::response::set_next_record_id(END_OF_RECORD,
1156 resp); // last record
Ratan Guptae0cc8552018-01-22 14:23:04 +05301157 }
1158 else
1159 {
1160 get_sdr::response::set_next_record_id(
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -08001161 (ENTITY_RECORD_ID_START + entity->first), resp);
Ratan Guptae0cc8552018-01-22 14:23:04 +05301162 }
1163
Emily Shaffer0fbdbce2018-09-27 09:30:41 -07001164 // Check for invalid offset size
1165 if (req->offset > sizeof(record))
Ratan Guptae0cc8552018-01-22 14:23:04 +05301166 {
Emily Shaffer0fbdbce2018-09-27 09:30:41 -07001167 return IPMI_CC_PARM_OUT_OF_RANGE;
Ratan Guptae0cc8552018-01-22 14:23:04 +05301168 }
1169
Emily Shaffer0fbdbce2018-09-27 09:30:41 -07001170 dataLength = std::min(static_cast<size_t>(req->bytes_to_read),
1171 sizeof(record) - req->offset);
Ratan Guptae0cc8552018-01-22 14:23:04 +05301172
Patrick Ventureb51bf9c2018-09-10 15:53:14 -07001173 std::memcpy(resp->record_data,
Jason M. Bills1cd85962018-10-05 12:04:01 -07001174 reinterpret_cast<uint8_t*>(&record) + req->offset, dataLength);
Ratan Guptae0cc8552018-01-22 14:23:04 +05301175
1176 *data_len = dataLength;
1177 *data_len += 2; // additional 2 bytes for next record ID
1178
1179 return IPMI_CC_OK;
1180}
1181
Emily Shafferbbef71c2017-05-08 16:36:17 -07001182ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1183 ipmi_request_t request, ipmi_response_t response,
1184 ipmi_data_len_t data_len, ipmi_context_t context)
1185{
1186 ipmi_ret_t ret = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001187 get_sdr::GetSdrReq* req = (get_sdr::GetSdrReq*)request;
1188 get_sdr::GetSdrResp* resp = (get_sdr::GetSdrResp*)response;
Patrick Venture38426dd2019-07-30 15:22:29 -07001189
1190 // Note: we use an iterator so we can provide the next ID at the end of
1191 // the call.
Patrick Venturedb0cbe62019-09-09 14:47:22 -07001192 auto sensor = ipmi::sensor::sensors.begin();
Patrick Venture38426dd2019-07-30 15:22:29 -07001193 auto recordID = get_sdr::request::get_record_id(req);
1194
1195 // At the beginning of a scan, the host side will send us id=0.
1196 if (recordID != 0)
Emily Shafferbbef71c2017-05-08 16:36:17 -07001197 {
Patrick Venture38426dd2019-07-30 15:22:29 -07001198 // recordID 0 to 255 means it is a FULL record.
1199 // recordID 256 to 511 means it is a FRU record.
1200 // recordID greater then 511 means it is a Entity Association
1201 // record. Currently we are supporting three record types: FULL
1202 // record, FRU record and Enttiy Association record.
1203 if (recordID >= ENTITY_RECORD_ID_START)
Emily Shafferbbef71c2017-05-08 16:36:17 -07001204 {
Patrick Venture38426dd2019-07-30 15:22:29 -07001205 return ipmi_entity_get_sdr(request, response, data_len);
Emily Shafferbbef71c2017-05-08 16:36:17 -07001206 }
Patrick Venture38426dd2019-07-30 15:22:29 -07001207 else if (recordID >= FRU_RECORD_ID_START &&
1208 recordID < ENTITY_RECORD_ID_START)
Jaghathiswari Rankappagounder Natarajan0780df12019-02-06 15:29:24 -08001209 {
Patrick Venture38426dd2019-07-30 15:22:29 -07001210 return ipmi_fru_get_sdr(request, response, data_len);
Emily Shafferbbef71c2017-05-08 16:36:17 -07001211 }
1212 else
1213 {
Patrick Venturedb0cbe62019-09-09 14:47:22 -07001214 sensor = ipmi::sensor::sensors.find(recordID);
1215 if (sensor == ipmi::sensor::sensors.end())
Patrick Venture38426dd2019-07-30 15:22:29 -07001216 {
1217 return IPMI_CC_SENSOR_INVALID;
1218 }
Emily Shafferbbef71c2017-05-08 16:36:17 -07001219 }
Emily Shafferbbef71c2017-05-08 16:36:17 -07001220 }
1221
Patrick Venture38426dd2019-07-30 15:22:29 -07001222 uint8_t sensor_id = sensor->first;
1223
Lei YU14a47812021-09-17 15:58:04 +08001224 auto it = sdrCacheMap.find(sensor_id);
1225 if (it == sdrCacheMap.end())
Patrick Venture38426dd2019-07-30 15:22:29 -07001226 {
Lei YU14a47812021-09-17 15:58:04 +08001227 /* Header */
1228 get_sdr::SensorDataFullRecord record = {0};
1229 get_sdr::header::set_record_id(sensor_id, &(record.header));
1230 record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1
1231 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1232 record.header.record_length = sizeof(record.key) + sizeof(record.body);
1233
1234 /* Key */
1235 get_sdr::key::set_owner_id_bmc(&(record.key));
1236 record.key.sensor_number = sensor_id;
1237
1238 /* Body */
1239 record.body.entity_id = sensor->second.entityType;
1240 record.body.sensor_type = sensor->second.sensorType;
1241 record.body.event_reading_type = sensor->second.sensorReadingType;
1242 record.body.entity_instance = sensor->second.instance;
1243 if (ipmi::sensor::Mutability::Write ==
1244 (sensor->second.mutability & ipmi::sensor::Mutability::Write))
1245 {
1246 get_sdr::body::init_settable_state(true, &(record.body));
1247 }
1248
1249 // Set the type-specific details given the DBus interface
1250 populate_record_from_dbus(&(record.body), &(sensor->second), data_len);
1251 sdrCacheMap[sensor_id] = std::move(record);
Patrick Venture38426dd2019-07-30 15:22:29 -07001252 }
1253
Lei YU14a47812021-09-17 15:58:04 +08001254 const auto& record = sdrCacheMap[sensor_id];
Patrick Venture38426dd2019-07-30 15:22:29 -07001255
Patrick Venturedb0cbe62019-09-09 14:47:22 -07001256 if (++sensor == ipmi::sensor::sensors.end())
Patrick Venture38426dd2019-07-30 15:22:29 -07001257 {
1258 // we have reached till end of sensor, so assign the next record id
1259 // to 256(Max Sensor ID = 255) + FRU ID(may start with 0).
1260 auto next_record_id = (frus.size())
1261 ? frus.begin()->first + FRU_RECORD_ID_START
1262 : END_OF_RECORD;
1263
1264 get_sdr::response::set_next_record_id(next_record_id, resp);
1265 }
1266 else
1267 {
1268 get_sdr::response::set_next_record_id(sensor->first, resp);
1269 }
1270
1271 if (req->offset > sizeof(record))
1272 {
1273 return IPMI_CC_PARM_OUT_OF_RANGE;
1274 }
1275
1276 // data_len will ultimately be the size of the record, plus
1277 // the size of the next record ID:
1278 *data_len = std::min(static_cast<size_t>(req->bytes_to_read),
1279 sizeof(record) - req->offset);
1280
1281 std::memcpy(resp->record_data,
Lei YU14a47812021-09-17 15:58:04 +08001282 reinterpret_cast<const uint8_t*>(&record) + req->offset,
1283 *data_len);
Patrick Venture38426dd2019-07-30 15:22:29 -07001284
1285 // data_len should include the LSB and MSB:
1286 *data_len +=
1287 sizeof(resp->next_record_id_lsb) + sizeof(resp->next_record_id_msb);
1288
Emily Shafferbbef71c2017-05-08 16:36:17 -07001289 return ret;
1290}
1291
Jia, Chunhui3342a8e2018-12-29 13:32:26 +08001292static bool isFromSystemChannel()
1293{
1294 // TODO we could not figure out where the request is from based on IPMI
1295 // command handler parameters. because of it, we can not differentiate
1296 // request from SMS/SMM or IPMB channel
1297 return true;
1298}
1299
1300ipmi_ret_t ipmicmdPlatformEvent(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1301 ipmi_request_t request,
1302 ipmi_response_t response,
1303 ipmi_data_len_t dataLen, ipmi_context_t context)
1304{
1305 uint16_t generatorID;
1306 size_t count;
1307 bool assert = true;
1308 std::string sensorPath;
1309 size_t paraLen = *dataLen;
1310 PlatformEventRequest* req;
1311 *dataLen = 0;
1312
1313 if ((paraLen < selSystemEventSizeWith1Bytes) ||
1314 (paraLen > selSystemEventSizeWith3Bytes))
1315 {
1316 return IPMI_CC_REQ_DATA_LEN_INVALID;
1317 }
1318
1319 if (isFromSystemChannel())
1320 { // first byte for SYSTEM Interface is Generator ID
1321 // +1 to get common struct
1322 req = reinterpret_cast<PlatformEventRequest*>((uint8_t*)request + 1);
1323 // Capture the generator ID
1324 generatorID = *reinterpret_cast<uint8_t*>(request);
1325 // Platform Event usually comes from other firmware, like BIOS.
1326 // Unlike BMC sensor, it does not have BMC DBUS sensor path.
1327 sensorPath = "System";
1328 }
1329 else
1330 {
1331 req = reinterpret_cast<PlatformEventRequest*>(request);
1332 // TODO GenratorID for IPMB is combination of RqSA and RqLUN
1333 generatorID = 0xff;
1334 sensorPath = "IPMB";
1335 }
1336 // Content of event data field depends on sensor class.
1337 // When data0 bit[5:4] is non-zero, valid data counts is 3.
1338 // When data0 bit[7:6] is non-zero, valid data counts is 2.
1339 if (((req->data[0] & byte3EnableMask) != 0 &&
1340 paraLen < selSystemEventSizeWith3Bytes) ||
1341 ((req->data[0] & byte2EnableMask) != 0 &&
1342 paraLen < selSystemEventSizeWith2Bytes))
1343 {
1344 return IPMI_CC_REQ_DATA_LEN_INVALID;
1345 }
1346
1347 // Count bytes of Event Data
1348 if ((req->data[0] & byte3EnableMask) != 0)
1349 {
1350 count = 3;
1351 }
1352 else if ((req->data[0] & byte2EnableMask) != 0)
1353 {
1354 count = 2;
1355 }
1356 else
1357 {
1358 count = 1;
1359 }
1360 assert = req->eventDirectionType & directionMask ? false : true;
1361 std::vector<uint8_t> eventData(req->data, req->data + count);
1362
1363 sdbusplus::bus::bus dbus(bus);
1364 std::string service =
1365 ipmi::getService(dbus, ipmiSELAddInterface, ipmiSELPath);
1366 sdbusplus::message::message writeSEL = dbus.new_method_call(
1367 service.c_str(), ipmiSELPath, ipmiSELAddInterface, "IpmiSelAdd");
1368 writeSEL.append(ipmiSELAddMessage, sensorPath, eventData, assert,
1369 generatorID);
1370 try
1371 {
1372 dbus.call(writeSEL);
1373 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001374 catch (const sdbusplus::exception_t& e)
Jia, Chunhui3342a8e2018-12-29 13:32:26 +08001375 {
1376 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1377 return IPMI_CC_UNSPECIFIED_ERROR;
1378 }
1379 return IPMI_CC_OK;
1380}
1381
Chris Austenac4604a2015-10-13 12:43:27 -05001382void register_netfn_sen_functions()
1383{
Willy Tud351a722021-08-12 14:33:40 -07001384 // Handlers with dbus-sdr handler implementation.
1385 // Do not register the hander if it dynamic sensors stack is used.
Deepak Kumar Sahua8be7dc2019-05-07 14:26:53 +00001386
Willy Tud351a722021-08-12 14:33:40 -07001387#ifndef FEATURE_DYNAMIC_SENSORS
Lei YUbe5c6b22021-09-16 15:46:20 +08001388
Lei YU962e68b2021-09-16 16:25:34 +08001389#ifdef FEATURE_SENSORS_CACHE
Lei YUbe5c6b22021-09-16 15:46:20 +08001390 // Initialize the sensor matches
1391 initSensorMatches();
Lei YU962e68b2021-09-16 16:25:34 +08001392#endif
Lei YUbe5c6b22021-09-16 15:46:20 +08001393
Tom05732372016-09-06 17:21:23 +05301394 // <Set Sensor Reading and Event Status>
Deepak Kumar Sahu9da3a752019-05-21 00:45:14 +00001395 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1396 ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
1397 ipmi::Privilege::Operator, ipmiSetSensorReading);
Tom05732372016-09-06 17:21:23 +05301398 // <Get Sensor Reading>
jayaprakash Mutyala4c3feba2019-07-16 00:14:35 +00001399 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1400 ipmi::sensor_event::cmdGetSensorReading,
1401 ipmi::Privilege::User, ipmiSensorGetSensorReading);
Emily Shaffera344afc2017-04-13 15:09:39 -07001402
Tom Joseph5ca50952018-02-22 00:33:38 +05301403 // <Reserve Device SDR Repository>
jayaprakash Mutyalad9578232019-05-13 20:22:50 +00001404 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1405 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
1406 ipmi::Privilege::User, ipmiSensorReserveSdr);
Chris Austen10ccc0f2015-12-10 18:27:04 -06001407
Tom Joseph5ca50952018-02-22 00:33:38 +05301408 // <Get Device SDR Info>
jayaprakash Mutyalad9578232019-05-13 20:22:50 +00001409 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1410 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1411 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
Emily Shafferbbef71c2017-05-08 16:36:17 -07001412
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -06001413 // <Get Sensor Thresholds>
jayaprakash Mutyala996c9792019-05-03 15:56:48 +00001414 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1415 ipmi::sensor_event::cmdGetSensorThreshold,
1416 ipmi::Privilege::User, ipmiSensorGetSensorThresholds);
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -06001417
Lotus Xuf93da662021-10-18 17:20:06 +08001418 // <Set Sensor Thresholds>
1419 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1420 ipmi::sensor_event::cmdSetSensorThreshold,
1421 ipmi::Privilege::User, ipmiSenSetSensorThresholds);
Willy Tud351a722021-08-12 14:33:40 -07001422#endif
1423
1424 // Common Handers used by both implementation.
1425
1426 // <Platform Event Message>
1427 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_PLATFORM_EVENT, nullptr,
1428 ipmicmdPlatformEvent, PRIVILEGE_OPERATOR);
1429
1430 // <Get Sensor Type>
1431 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1432 ipmi::sensor_event::cmdGetSensorType,
1433 ipmi::Privilege::User, ipmiGetSensorType);
1434
1435 // <Get Device SDR>
1436 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_DEVICE_SDR, nullptr,
1437 ipmi_sen_get_sdr, PRIVILEGE_USER);
Chris Austenac4604a2015-10-13 12:43:27 -05001438 return;
1439}