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