| Andrew Jeffery | e73bd0a | 2023-01-25 10:39:57 +1030 | [diff] [blame] | 1 | #include "IpmbSDRSensor.hpp" | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 2 |  | 
| Ed Tanous | eacbfdd | 2024-04-04 12:00:24 -0700 | [diff] [blame] | 3 | #include <sdbusplus/asio/connection.hpp> | 
|  | 4 |  | 
|  | 5 | #include <cmath> | 
|  | 6 | #include <cstddef> | 
|  | 7 | #include <cstdint> | 
|  | 8 | #include <functional> | 
|  | 9 | #include <iostream> | 
|  | 10 | #include <memory> | 
|  | 11 | #include <string> | 
|  | 12 | #include <utility> | 
|  | 13 | #include <vector> | 
|  | 14 |  | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 15 | const constexpr char* ipmbService = "xyz.openbmc_project.Ipmi.Channel.Ipmb"; | 
|  | 16 | const constexpr char* ipmbDbusPath = "/xyz/openbmc_project/Ipmi/Channel/Ipmb"; | 
|  | 17 | const constexpr char* ipmbInterface = "org.openbmc.Ipmb"; | 
|  | 18 | const constexpr char* ipmbMethod = "sendRequest"; | 
|  | 19 | static constexpr uint8_t lun = 0; | 
|  | 20 |  | 
|  | 21 | IpmbSDRDevice::IpmbSDRDevice( | 
|  | 22 | std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, | 
|  | 23 | uint8_t cmdAddr) : | 
|  | 24 | commandAddress(cmdAddr << 2), | 
|  | 25 | hostIndex(cmdAddr + 1), conn(dbusConnection) | 
|  | 26 | {} | 
|  | 27 |  | 
|  | 28 | bool validateStatus(boost::system::error_code ec, | 
|  | 29 | const IpmbMethodType& response, int hostIndex) | 
|  | 30 | { | 
|  | 31 | if (ec) | 
|  | 32 | { | 
|  | 33 | return false; | 
|  | 34 | } | 
|  | 35 |  | 
|  | 36 | const int status = std::get<0>(response); | 
|  | 37 | if (status != 0) | 
|  | 38 | { | 
|  | 39 | std::cerr << "Error reading from IPMB SDR for host " << hostIndex | 
|  | 40 | << "\n"; | 
|  | 41 | return false; | 
|  | 42 | } | 
|  | 43 | return true; | 
|  | 44 | } | 
|  | 45 |  | 
|  | 46 | /* This function will store the record count of the SDR sensors for each IPMB | 
|  | 47 | * bus */ | 
|  | 48 | void IpmbSDRDevice::getSDRRepositoryInfo() | 
|  | 49 | { | 
|  | 50 | std::weak_ptr<IpmbSDRDevice> weakRef = weak_from_this(); | 
|  | 51 |  | 
|  | 52 | conn->async_method_call( | 
|  | 53 | [weakRef](boost::system::error_code ec, | 
|  | 54 | const IpmbMethodType& response) { | 
|  | 55 | auto self = weakRef.lock(); | 
|  | 56 | if (!self) | 
|  | 57 | { | 
|  | 58 | return; | 
|  | 59 | } | 
|  | 60 |  | 
|  | 61 | auto status = std::bind_front(validateStatus, ec, response); | 
|  | 62 | if (!status(self->hostIndex)) | 
|  | 63 | { | 
|  | 64 | return; | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | const std::vector<uint8_t>& data = std::get<5>(response); | 
|  | 68 | const size_t sdrInfoDataSize = 14; | 
|  | 69 |  | 
|  | 70 | if (data.size() < sdrInfoDataSize) | 
|  | 71 | { | 
|  | 72 | std::cerr << " IPMB Get SDR Repository Info data is empty for host " | 
|  | 73 | << self->hostIndex << "\n"; | 
|  | 74 | return; | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | constexpr uint8_t recordCountLSB = 1; | 
|  | 78 | constexpr uint8_t recordCountMSB = 2; | 
|  | 79 |  | 
| Patrick Williams | 779c96a | 2023-05-10 07:50:42 -0500 | [diff] [blame] | 80 | uint16_t recordCount = (data[recordCountMSB] << 8) | | 
|  | 81 | data[recordCountLSB]; | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 82 |  | 
|  | 83 | self->reserveSDRRepository(recordCount); | 
| Patrick Williams | 597e842 | 2023-10-20 11:19:01 -0500 | [diff] [blame] | 84 | }, | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 85 | ipmbService, ipmbDbusPath, ipmbInterface, ipmbMethod, commandAddress, | 
|  | 86 | sdr::netfnStorageReq, lun, sdr::cmdStorageGetSdrInfo, sdrCommandData); | 
|  | 87 | } | 
|  | 88 |  | 
|  | 89 | /* This function will store the reserve ID for each IPMB bus index */ | 
|  | 90 | void IpmbSDRDevice::reserveSDRRepository(uint16_t recordCount) | 
|  | 91 | { | 
|  | 92 | std::weak_ptr<IpmbSDRDevice> weakRef = weak_from_this(); | 
|  | 93 |  | 
|  | 94 | conn->async_method_call( | 
|  | 95 | [weakRef, recordCount](boost::system::error_code ec, | 
|  | 96 | const IpmbMethodType& response) { | 
|  | 97 | auto self = weakRef.lock(); | 
|  | 98 | if (!self) | 
|  | 99 | { | 
|  | 100 | return; | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | auto status = std::bind_front(validateStatus, ec, response); | 
|  | 104 | if (!status(self->hostIndex)) | 
|  | 105 | { | 
|  | 106 | return; | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | const std::vector<uint8_t>& data = std::get<5>(response); | 
|  | 110 | const size_t sdrReserveDataSize = 2; | 
|  | 111 |  | 
|  | 112 | if (data.size() < sdrReserveDataSize) | 
|  | 113 | { | 
|  | 114 | std::cerr << " IPMB SDR Reserve Repository data is empty for host " | 
|  | 115 | << self->hostIndex << "\n"; | 
|  | 116 | return; | 
|  | 117 | } | 
|  | 118 | uint8_t resrvIDLSB = data[0]; | 
|  | 119 | uint8_t resrvIDMSB = data[1]; | 
|  | 120 |  | 
|  | 121 | self->getSDRSensorData(recordCount, resrvIDLSB, resrvIDMSB); | 
| Patrick Williams | 597e842 | 2023-10-20 11:19:01 -0500 | [diff] [blame] | 122 | }, | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 123 | ipmbService, ipmbDbusPath, ipmbInterface, ipmbMethod, commandAddress, | 
|  | 124 | sdr::netfnStorageReq, lun, sdr::cmdStorageReserveSdr, sdrCommandData); | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | /* This function will read all the information related to the sensor | 
|  | 128 | * such as name, threshold value, unit, device address, SDR type */ | 
|  | 129 | void IpmbSDRDevice::getSDRSensorData(uint16_t recordCount, uint8_t resrvIDLSB, | 
|  | 130 | uint8_t resrvIDMSB) | 
|  | 131 | { | 
|  | 132 | std::weak_ptr<IpmbSDRDevice> weakRef = weak_from_this(); | 
|  | 133 |  | 
|  | 134 | uint8_t loopCount = sdr::perCountByte * iCnt; | 
|  | 135 | std::vector<uint8_t> commandData = {resrvIDLSB,      resrvIDMSB, | 
|  | 136 | nextRecordIDLSB, nextRecordIDMSB, | 
|  | 137 | loopCount,       sdr::perCountByte}; | 
|  | 138 |  | 
|  | 139 | conn->async_method_call( | 
|  | 140 | [weakRef, recordCount, resrvIDLSB, resrvIDMSB]( | 
|  | 141 | boost::system::error_code ec, const IpmbMethodType& response) { | 
|  | 142 | auto self = weakRef.lock(); | 
|  | 143 | if (!self) | 
|  | 144 | { | 
|  | 145 | return; | 
|  | 146 | } | 
|  | 147 |  | 
|  | 148 | auto status = std::bind_front(validateStatus, ec, response); | 
|  | 149 | if (!status(self->hostIndex)) | 
|  | 150 | { | 
|  | 151 | return; | 
|  | 152 | } | 
|  | 153 |  | 
|  | 154 | const std::vector<uint8_t>& data = std::get<5>(response); | 
|  | 155 | const size_t sdrSensorDataSize = 18; | 
|  | 156 |  | 
|  | 157 | if (data.size() < sdrSensorDataSize) | 
|  | 158 | { | 
|  | 159 | std::cerr << "IPMB SDR sensor data is empty for host " | 
|  | 160 | << self->hostIndex << "\n"; | 
|  | 161 | return; | 
|  | 162 | } | 
|  | 163 |  | 
|  | 164 | self->handleSDRData(data, recordCount, resrvIDLSB, resrvIDMSB); | 
| Patrick Williams | 597e842 | 2023-10-20 11:19:01 -0500 | [diff] [blame] | 165 | }, | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 166 | ipmbService, ipmbDbusPath, ipmbInterface, ipmbMethod, commandAddress, | 
|  | 167 | sdr::netfnStorageReq, lun, sdr::cmdStorageGetSdr, commandData); | 
|  | 168 | } | 
|  | 169 |  | 
|  | 170 | /* This function will handle the sensor data received by IPMB response */ | 
|  | 171 | void IpmbSDRDevice::handleSDRData(const std::vector<uint8_t>& data, | 
|  | 172 | uint16_t recordCount, uint8_t resrvIDLSB, | 
|  | 173 | uint8_t resrvIDMSB) | 
|  | 174 | { | 
|  | 175 | sdrData.insert(sdrData.end(), data.begin(), data.end()); | 
|  | 176 |  | 
|  | 177 | /* dataLength represents the size of data for SDR types */ | 
|  | 178 | uint8_t dataLength = sdrData[sdr::dataLengthByte] + sdr::dataLengthByte + 1; | 
|  | 179 |  | 
|  | 180 | /*  If sdrData size is less than dataLength, it will call getSDRSensorData | 
|  | 181 | *  function recursively till all the data is received. | 
|  | 182 | */ | 
|  | 183 | if (sdrData.size() < dataLength) | 
|  | 184 | { | 
|  | 185 | iCnt++; | 
|  | 186 | getSDRSensorData(recordCount, resrvIDLSB, resrvIDMSB); | 
|  | 187 | } | 
|  | 188 | else | 
|  | 189 | { | 
|  | 190 | /*  After all the data is received, it is passed to checkSDRData | 
|  | 191 | *  function. Next sensor record ID is stored based on the previous | 
|  | 192 | *  record ID. Vector of sdrData is cleared to store next sensor data. | 
|  | 193 | *  validRecordCount is incremented and getSDRSensorData function is | 
|  | 194 | *  called to proceed with next set of sensors. | 
|  | 195 | */ | 
|  | 196 | checkSDRData(sdrData, dataLength); | 
|  | 197 | iCnt = 0; | 
|  | 198 | nextRecordIDLSB = sdrData[sdr::sdrNxtRecLSB]; | 
|  | 199 | nextRecordIDMSB = sdrData[sdr::sdrNxtRecMSB]; | 
|  | 200 | sdrData.clear(); | 
|  | 201 |  | 
|  | 202 | if (validRecordCount == recordCount) | 
|  | 203 | { | 
|  | 204 | /* Once all the sensors are read and recordCount matched, it will | 
|  | 205 | * return. */ | 
|  | 206 | nextRecordIDLSB = 0; | 
|  | 207 | nextRecordIDMSB = 0; | 
|  | 208 | return; | 
|  | 209 | } | 
|  | 210 | validRecordCount++; | 
|  | 211 | getSDRSensorData(recordCount, resrvIDLSB, resrvIDMSB); | 
|  | 212 | } | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | /* This function will convert the SDR sensor data such as sensor unit, name, ID, | 
|  | 216 | * type from decimal to readable format */ | 
|  | 217 | void IpmbSDRDevice::checkSDRData(std::vector<uint8_t>& sdrDataBytes, | 
|  | 218 | uint8_t dataLength) const | 
|  | 219 | { | 
|  | 220 | if (sdrDataBytes.size() < dataLength) | 
|  | 221 | { | 
|  | 222 | return; | 
|  | 223 | } | 
|  | 224 |  | 
|  | 225 | /* sdrType represents the SDR Type (Byte 5) such as 1, 2, 3 */ | 
|  | 226 | uint8_t sdrType = sdrDataBytes[sdr::sdrType]; | 
|  | 227 | if (sdrType != static_cast<uint8_t>(SDRType::sdrType01)) | 
|  | 228 | { | 
|  | 229 | return; | 
|  | 230 | } | 
|  | 231 |  | 
|  | 232 | /*  dataLen represents the data length (Byte 6) for SDR sensor */ | 
|  | 233 | int dataLen = sdrDataBytes[sdr::dataLengthByte]; | 
|  | 234 |  | 
|  | 235 | /* iStrLen represents the length of the sensor name for SDR Type 1 */ | 
|  | 236 | const uint8_t sdrLenBit = 0x1F; | 
|  | 237 | int strLen = (sdrDataBytes[sdrtype01::nameLengthByte]) & (sdrLenBit); | 
|  | 238 |  | 
|  | 239 | /* iStrAddr represents the starting byte (Byte 56) for SDR sensor name */ | 
| Patrick Williams | 779c96a | 2023-05-10 07:50:42 -0500 | [diff] [blame] | 240 | int strAddr = dataLen + ((dataLen / (sdr::perCountByte)) * 4) - | 
|  | 241 | (strLen - 1); | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 242 |  | 
|  | 243 | /* Below for loop will convert the bytes to string and form a sensor name */ | 
|  | 244 |  | 
|  | 245 | std::string tempName(sdrDataBytes.begin() + strAddr, | 
|  | 246 | sdrDataBytes.begin() + strAddr + strLen); | 
|  | 247 |  | 
|  | 248 | checkSDRType01Threshold(sdrDataBytes, (hostIndex - 1), tempName); | 
|  | 249 | } | 
|  | 250 |  | 
|  | 251 | /* This function will convert the raw value of threshold for each sensor */ | 
|  | 252 | void IpmbSDRDevice::checkSDRType01Threshold(std::vector<uint8_t>& sdrDataBytes, | 
|  | 253 | int busIndex, std::string tempName) | 
|  | 254 | { | 
|  | 255 | const uint8_t bitShiftMsb = 2; | 
|  | 256 | const uint8_t sdrThresAccess = 0x0C; | 
|  | 257 |  | 
|  | 258 | /* linear represents the sensor's linearization (Byte 27) */ | 
|  | 259 | uint8_t linear = sdrDataBytes[sdrtype01::sdrLinearByte]; | 
|  | 260 | if (linear != 0) | 
|  | 261 | { | 
|  | 262 | return; | 
|  | 263 | } | 
|  | 264 |  | 
|  | 265 | /* sdrSensCapability (Byte 13) and(&) with sdrThresAccess(0x0C) will declare | 
|  | 266 | * whether threshold is present for each sensor */ | 
| Patrick Williams | 779c96a | 2023-05-10 07:50:42 -0500 | [diff] [blame] | 267 | int threshold = (sdrDataBytes[sdrtype01::sensorCapability]) & | 
|  | 268 | (sdrThresAccess); | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 269 |  | 
|  | 270 | /* mData        - 10 bits | 
|  | 271 | * mDataByte    - Byte 28 - 8 bits LSB | 
|  | 272 | * mTolDataByte - Byte 29 - 2 bits MSB [7-6] | 
|  | 273 | */ | 
| Patrick Williams | 779c96a | 2023-05-10 07:50:42 -0500 | [diff] [blame] | 274 | uint16_t mData = ((sdrDataBytes[sdrtype01::mTolDataByte] & 0xC0) | 
|  | 275 | << bitShiftMsb) | | 
|  | 276 | sdrDataBytes[sdrtype01::mDataByte]; | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 277 |  | 
|  | 278 | /* bData        - 10 bits | 
|  | 279 | * bDataByte    - Byte 30 - 8 bits LSB | 
|  | 280 | * bAcuDataByte - Byte 31 - 2 bits MSB [7-6] | 
|  | 281 | */ | 
| Patrick Williams | 779c96a | 2023-05-10 07:50:42 -0500 | [diff] [blame] | 282 | uint16_t bData = ((sdrDataBytes[sdrtype01::bAcuDataByte] & 0xC0) | 
|  | 283 | << bitShiftMsb) | | 
|  | 284 | sdrDataBytes[sdrtype01::bDataByte]; | 
| Jayashree Dhanapal | 3746c55 | 2022-03-21 14:45:52 +0530 | [diff] [blame] | 285 |  | 
|  | 286 | /* rbExpDataByte (Byte 33) represents the exponent value | 
|  | 287 | *  Bit [3-0] - B Exponent 2's complement signed bit. | 
|  | 288 | *  Bit [7-4] - R Exponent 2's complement signed bit. | 
|  | 289 | */ | 
|  | 290 | int8_t bExpVal = sdrDataBytes[sdrtype01::rbExpDataByte] & 0xF; | 
|  | 291 | if (bExpVal > 7) | 
|  | 292 | { | 
|  | 293 | bExpVal = (~bExpVal + 1) & 0xF; | 
|  | 294 | } | 
|  | 295 |  | 
|  | 296 | /* Shifting the data to right by 4, since rExpVal has 4 bits from 4 to 7 in | 
|  | 297 | * byte 33 */ | 
|  | 298 | int8_t rExpVal = (sdrDataBytes[sdrtype01::rbExpDataByte] >> 4) & 0xF; | 
|  | 299 | if (rExpVal > 7) | 
|  | 300 | { | 
|  | 301 | rExpVal = (~rExpVal + 1) & 0xF; | 
|  | 302 | rExpVal = -rExpVal; | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | /* Sensor Threshold Reading Conversion | 
|  | 306 | * | 
|  | 307 | *  Y = ((Mx + (B * 10^K1)) * (10^K2)) | 
|  | 308 | * | 
|  | 309 | *  X  - Raw value of threshold | 
|  | 310 | *  M  - mData Value | 
|  | 311 | *  B  - bData Value | 
|  | 312 | *  K1 - Signed Exponent of bExpVal | 
|  | 313 | *  K2 - Signed Exponent of rExpVal | 
|  | 314 | */ | 
|  | 315 |  | 
|  | 316 | double bDataVal = bData * pow(10, bExpVal); | 
|  | 317 | double expVal = pow(10, rExpVal); | 
|  | 318 |  | 
|  | 319 | double thresUpCri = | 
|  | 320 | sensorValCalculation(mData, bDataVal, expVal, | 
|  | 321 | sdrDataBytes[sdrtype01::upperCriticalThreshold]); | 
|  | 322 | double thresLoCri = | 
|  | 323 | sensorValCalculation(mData, bDataVal, expVal, | 
|  | 324 | sdrDataBytes[sdrtype01::lowerCriticalThreshold]); | 
|  | 325 |  | 
|  | 326 | struct SensorInfo temp; | 
|  | 327 |  | 
|  | 328 | temp.sensorReadName = std::move(tempName); | 
|  | 329 | temp.sensorUnit = sdrDataBytes[sdrtype01::sdrUnitType]; | 
|  | 330 |  | 
|  | 331 | temp.thresUpperCri = thresUpCri; | 
|  | 332 | temp.thresLowerCri = thresLoCri; | 
|  | 333 |  | 
|  | 334 | temp.sensorNumber = sdrDataBytes[sdr::sdrSensorNum]; | 
|  | 335 | temp.sensCap = threshold; | 
|  | 336 |  | 
|  | 337 | sensorRecord[busIndex].emplace_back(std::move(temp)); | 
|  | 338 |  | 
|  | 339 | SensorValConversion val = {mData, bDataVal, expVal, | 
|  | 340 | sdrDataBytes[sdrtype01::sdrNegHandle]}; | 
|  | 341 |  | 
|  | 342 | sensorValRecord[busIndex][sdrDataBytes[sdr::sdrSensorNum]] = val; | 
|  | 343 | } | 
|  | 344 |  | 
|  | 345 | /* This function will calculate the sensor's threshold value */ | 
|  | 346 | double IpmbSDRDevice::sensorValCalculation(uint16_t mValue, double bValue, | 
|  | 347 | double expValue, double value) | 
|  | 348 | { | 
|  | 349 | double sensorValue = ((mValue * value) + bValue) * expValue; | 
|  | 350 | return sensorValue; | 
|  | 351 | } |