blob: d0ab8849a1510ab820151bcad75d27ad78175807 [file] [log] [blame]
Andrew Jefferye73bd0a2023-01-25 10:39:57 +10301#include "IpmbSDRSensor.hpp"
Jayashree Dhanapal3746c552022-03-21 14:45:52 +05302
3const constexpr char* ipmbService = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
4const constexpr char* ipmbDbusPath = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
5const constexpr char* ipmbInterface = "org.openbmc.Ipmb";
6const constexpr char* ipmbMethod = "sendRequest";
7static constexpr uint8_t lun = 0;
8
9IpmbSDRDevice::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
16bool 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 */
36void 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
Patrick Williams779c96a2023-05-10 07:50:42 -050068 uint16_t recordCount = (data[recordCountMSB] << 8) |
69 data[recordCountLSB];
Jayashree Dhanapal3746c552022-03-21 14:45:52 +053070
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 */
78void 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 */
117void 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 */
159void 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 */
205void 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 */
Patrick Williams779c96a2023-05-10 07:50:42 -0500228 int strAddr = dataLen + ((dataLen / (sdr::perCountByte)) * 4) -
229 (strLen - 1);
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530230
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 */
240void 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 */
Patrick Williams779c96a2023-05-10 07:50:42 -0500255 int threshold = (sdrDataBytes[sdrtype01::sensorCapability]) &
256 (sdrThresAccess);
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530257
258 /* mData - 10 bits
259 * mDataByte - Byte 28 - 8 bits LSB
260 * mTolDataByte - Byte 29 - 2 bits MSB [7-6]
261 */
Patrick Williams779c96a2023-05-10 07:50:42 -0500262 uint16_t mData = ((sdrDataBytes[sdrtype01::mTolDataByte] & 0xC0)
263 << bitShiftMsb) |
264 sdrDataBytes[sdrtype01::mDataByte];
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530265
266 /* bData - 10 bits
267 * bDataByte - Byte 30 - 8 bits LSB
268 * bAcuDataByte - Byte 31 - 2 bits MSB [7-6]
269 */
Patrick Williams779c96a2023-05-10 07:50:42 -0500270 uint16_t bData = ((sdrDataBytes[sdrtype01::bAcuDataByte] & 0xC0)
271 << bitShiftMsb) |
272 sdrDataBytes[sdrtype01::bDataByte];
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530273
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 */
334double IpmbSDRDevice::sensorValCalculation(uint16_t mValue, double bValue,
335 double expValue, double value)
336{
337 double sensorValue = ((mValue * value) + bValue) * expValue;
338 return sensorValue;
339}