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