blob: 299ff800bee6700b1b714f97c7439c1c38f239c9 [file] [log] [blame]
#include "IpmbSDRSensor.hpp"
#include <sdbusplus/asio/connection.hpp>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <vector>
const constexpr char* ipmbService = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
const constexpr char* ipmbDbusPath = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
const constexpr char* ipmbInterface = "org.openbmc.Ipmb";
const constexpr char* ipmbMethod = "sendRequest";
static constexpr uint8_t lun = 0;
IpmbSDRDevice::IpmbSDRDevice(
std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
uint8_t cmdAddr) :
commandAddress(cmdAddr << 2),
hostIndex(cmdAddr + 1), conn(dbusConnection)
{}
bool validateStatus(boost::system::error_code ec,
const IpmbMethodType& response, int hostIndex)
{
if (ec)
{
return false;
}
const int status = std::get<0>(response);
if (status != 0)
{
std::cerr << "Error reading from IPMB SDR for host " << hostIndex
<< "\n";
return false;
}
return true;
}
/* This function will store the record count of the SDR sensors for each IPMB
* bus */
void IpmbSDRDevice::getSDRRepositoryInfo()
{
std::weak_ptr<IpmbSDRDevice> weakRef = weak_from_this();
conn->async_method_call(
[weakRef](boost::system::error_code ec,
const IpmbMethodType& response) {
auto self = weakRef.lock();
if (!self)
{
return;
}
auto status = std::bind_front(validateStatus, ec, response);
if (!status(self->hostIndex))
{
return;
}
const std::vector<uint8_t>& data = std::get<5>(response);
const size_t sdrInfoDataSize = 14;
if (data.size() < sdrInfoDataSize)
{
std::cerr << " IPMB Get SDR Repository Info data is empty for host "
<< self->hostIndex << "\n";
return;
}
constexpr uint8_t recordCountLSB = 1;
constexpr uint8_t recordCountMSB = 2;
uint16_t recordCount = (data[recordCountMSB] << 8) |
data[recordCountLSB];
self->reserveSDRRepository(recordCount);
},
ipmbService, ipmbDbusPath, ipmbInterface, ipmbMethod, commandAddress,
sdr::netfnStorageReq, lun, sdr::cmdStorageGetSdrInfo, sdrCommandData);
}
/* This function will store the reserve ID for each IPMB bus index */
void IpmbSDRDevice::reserveSDRRepository(uint16_t recordCount)
{
std::weak_ptr<IpmbSDRDevice> weakRef = weak_from_this();
conn->async_method_call(
[weakRef, recordCount](boost::system::error_code ec,
const IpmbMethodType& response) {
auto self = weakRef.lock();
if (!self)
{
return;
}
auto status = std::bind_front(validateStatus, ec, response);
if (!status(self->hostIndex))
{
return;
}
const std::vector<uint8_t>& data = std::get<5>(response);
const size_t sdrReserveDataSize = 2;
if (data.size() < sdrReserveDataSize)
{
std::cerr << " IPMB SDR Reserve Repository data is empty for host "
<< self->hostIndex << "\n";
return;
}
uint8_t resrvIDLSB = data[0];
uint8_t resrvIDMSB = data[1];
self->getSDRSensorData(recordCount, resrvIDLSB, resrvIDMSB);
},
ipmbService, ipmbDbusPath, ipmbInterface, ipmbMethod, commandAddress,
sdr::netfnStorageReq, lun, sdr::cmdStorageReserveSdr, sdrCommandData);
}
/* This function will read all the information related to the sensor
* such as name, threshold value, unit, device address, SDR type */
void IpmbSDRDevice::getSDRSensorData(uint16_t recordCount, uint8_t resrvIDLSB,
uint8_t resrvIDMSB)
{
std::weak_ptr<IpmbSDRDevice> weakRef = weak_from_this();
uint8_t loopCount = sdr::perCountByte * iCnt;
std::vector<uint8_t> commandData = {resrvIDLSB, resrvIDMSB,
nextRecordIDLSB, nextRecordIDMSB,
loopCount, sdr::perCountByte};
conn->async_method_call(
[weakRef, recordCount, resrvIDLSB, resrvIDMSB](
boost::system::error_code ec, const IpmbMethodType& response) {
auto self = weakRef.lock();
if (!self)
{
return;
}
auto status = std::bind_front(validateStatus, ec, response);
if (!status(self->hostIndex))
{
return;
}
const std::vector<uint8_t>& data = std::get<5>(response);
const size_t sdrSensorDataSize = 18;
if (data.size() < sdrSensorDataSize)
{
std::cerr << "IPMB SDR sensor data is empty for host "
<< self->hostIndex << "\n";
return;
}
self->handleSDRData(data, recordCount, resrvIDLSB, resrvIDMSB);
},
ipmbService, ipmbDbusPath, ipmbInterface, ipmbMethod, commandAddress,
sdr::netfnStorageReq, lun, sdr::cmdStorageGetSdr, commandData);
}
/* This function will handle the sensor data received by IPMB response */
void IpmbSDRDevice::handleSDRData(const std::vector<uint8_t>& data,
uint16_t recordCount, uint8_t resrvIDLSB,
uint8_t resrvIDMSB)
{
sdrData.insert(sdrData.end(), data.begin(), data.end());
/* dataLength represents the size of data for SDR types */
uint8_t dataLength = sdrData[sdr::dataLengthByte] + sdr::dataLengthByte + 1;
/* If sdrData size is less than dataLength, it will call getSDRSensorData
* function recursively till all the data is received.
*/
if (sdrData.size() < dataLength)
{
iCnt++;
getSDRSensorData(recordCount, resrvIDLSB, resrvIDMSB);
}
else
{
/* After all the data is received, it is passed to checkSDRData
* function. Next sensor record ID is stored based on the previous
* record ID. Vector of sdrData is cleared to store next sensor data.
* validRecordCount is incremented and getSDRSensorData function is
* called to proceed with next set of sensors.
*/
checkSDRData(sdrData, dataLength);
iCnt = 0;
nextRecordIDLSB = sdrData[sdr::sdrNxtRecLSB];
nextRecordIDMSB = sdrData[sdr::sdrNxtRecMSB];
sdrData.clear();
if (validRecordCount == recordCount)
{
/* Once all the sensors are read and recordCount matched, it will
* return. */
nextRecordIDLSB = 0;
nextRecordIDMSB = 0;
return;
}
validRecordCount++;
getSDRSensorData(recordCount, resrvIDLSB, resrvIDMSB);
}
}
/* This function will convert the SDR sensor data such as sensor unit, name, ID,
* type from decimal to readable format */
void IpmbSDRDevice::checkSDRData(std::vector<uint8_t>& sdrDataBytes,
uint8_t dataLength) const
{
if (sdrDataBytes.size() < dataLength)
{
return;
}
/* sdrType represents the SDR Type (Byte 5) such as 1, 2, 3 */
uint8_t sdrType = sdrDataBytes[sdr::sdrType];
if (sdrType != static_cast<uint8_t>(SDRType::sdrType01))
{
return;
}
/* dataLen represents the data length (Byte 6) for SDR sensor */
int dataLen = sdrDataBytes[sdr::dataLengthByte];
/* iStrLen represents the length of the sensor name for SDR Type 1 */
const uint8_t sdrLenBit = 0x1F;
int strLen = (sdrDataBytes[sdrtype01::nameLengthByte]) & (sdrLenBit);
/* iStrAddr represents the starting byte (Byte 56) for SDR sensor name */
int strAddr = dataLen + ((dataLen / (sdr::perCountByte)) * 4) -
(strLen - 1);
/* Below for loop will convert the bytes to string and form a sensor name */
std::string tempName(sdrDataBytes.begin() + strAddr,
sdrDataBytes.begin() + strAddr + strLen);
checkSDRType01Threshold(sdrDataBytes, (hostIndex - 1), tempName);
}
/* This function will convert the raw value of threshold for each sensor */
void IpmbSDRDevice::checkSDRType01Threshold(std::vector<uint8_t>& sdrDataBytes,
int busIndex, std::string tempName)
{
const uint8_t bitShiftMsb = 2;
const uint8_t sdrThresAccess = 0x0C;
/* linear represents the sensor's linearization (Byte 27) */
uint8_t linear = sdrDataBytes[sdrtype01::sdrLinearByte];
if (linear != 0)
{
return;
}
/* sdrSensCapability (Byte 13) and(&) with sdrThresAccess(0x0C) will declare
* whether threshold is present for each sensor */
int threshold = (sdrDataBytes[sdrtype01::sensorCapability]) &
(sdrThresAccess);
/* mData - 10 bits
* mDataByte - Byte 28 - 8 bits LSB
* mTolDataByte - Byte 29 - 2 bits MSB [7-6]
*/
uint16_t mData = ((sdrDataBytes[sdrtype01::mTolDataByte] & 0xC0)
<< bitShiftMsb) |
sdrDataBytes[sdrtype01::mDataByte];
/* bData - 10 bits
* bDataByte - Byte 30 - 8 bits LSB
* bAcuDataByte - Byte 31 - 2 bits MSB [7-6]
*/
uint16_t bData = ((sdrDataBytes[sdrtype01::bAcuDataByte] & 0xC0)
<< bitShiftMsb) |
sdrDataBytes[sdrtype01::bDataByte];
/* rbExpDataByte (Byte 33) represents the exponent value
* Bit [3-0] - B Exponent 2's complement signed bit.
* Bit [7-4] - R Exponent 2's complement signed bit.
*/
int8_t bExpVal = sdrDataBytes[sdrtype01::rbExpDataByte] & 0xF;
if (bExpVal > 7)
{
bExpVal = (~bExpVal + 1) & 0xF;
}
/* Shifting the data to right by 4, since rExpVal has 4 bits from 4 to 7 in
* byte 33 */
int8_t rExpVal = (sdrDataBytes[sdrtype01::rbExpDataByte] >> 4) & 0xF;
if (rExpVal > 7)
{
rExpVal = (~rExpVal + 1) & 0xF;
rExpVal = -rExpVal;
}
/* Sensor Threshold Reading Conversion
*
* Y = ((Mx + (B * 10^K1)) * (10^K2))
*
* X - Raw value of threshold
* M - mData Value
* B - bData Value
* K1 - Signed Exponent of bExpVal
* K2 - Signed Exponent of rExpVal
*/
double bDataVal = bData * pow(10, bExpVal);
double expVal = pow(10, rExpVal);
double thresUpCri =
sensorValCalculation(mData, bDataVal, expVal,
sdrDataBytes[sdrtype01::upperCriticalThreshold]);
double thresLoCri =
sensorValCalculation(mData, bDataVal, expVal,
sdrDataBytes[sdrtype01::lowerCriticalThreshold]);
struct SensorInfo temp;
temp.sensorReadName = std::move(tempName);
temp.sensorUnit = sdrDataBytes[sdrtype01::sdrUnitType];
temp.thresUpperCri = thresUpCri;
temp.thresLowerCri = thresLoCri;
temp.sensorNumber = sdrDataBytes[sdr::sdrSensorNum];
temp.sensCap = threshold;
sensorRecord[busIndex].emplace_back(std::move(temp));
SensorValConversion val = {mData, bDataVal, expVal,
sdrDataBytes[sdrtype01::sdrNegHandle]};
sensorValRecord[busIndex][sdrDataBytes[sdr::sdrSensorNum]] = val;
}
/* This function will calculate the sensor's threshold value */
double IpmbSDRDevice::sensorValCalculation(uint16_t mValue, double bValue,
double expValue, double value)
{
double sensorValue = ((mValue * value) + bValue) * expValue;
return sensorValue;
}