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