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