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), 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 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 << " 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); 122 }, 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); 165 }, 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 */ 240 int strAddr = dataLen + ((dataLen / (sdr::perCountByte)) * 4) - 241 (strLen - 1); 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 */ 267 int threshold = (sdrDataBytes[sdrtype01::sensorCapability]) & 268 (sdrThresAccess); 269 270 /* mData - 10 bits 271 * mDataByte - Byte 28 - 8 bits LSB 272 * mTolDataByte - Byte 29 - 2 bits MSB [7-6] 273 */ 274 uint16_t mData = ((sdrDataBytes[sdrtype01::mTolDataByte] & 0xC0) 275 << bitShiftMsb) | 276 sdrDataBytes[sdrtype01::mDataByte]; 277 278 /* bData - 10 bits 279 * bDataByte - Byte 30 - 8 bits LSB 280 * bAcuDataByte - Byte 31 - 2 bits MSB [7-6] 281 */ 282 uint16_t bData = ((sdrDataBytes[sdrtype01::bAcuDataByte] & 0xC0) 283 << bitShiftMsb) | 284 sdrDataBytes[sdrtype01::bDataByte]; 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 } 352