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