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