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