1 #include "IpmbSDRSensor.hpp"
2 
3 const constexpr char* ipmbService = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
4 const constexpr char* ipmbDbusPath = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
5 const constexpr char* ipmbInterface = "org.openbmc.Ipmb";
6 const constexpr char* ipmbMethod = "sendRequest";
7 static constexpr uint8_t lun = 0;
8 
9 IpmbSDRDevice::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 
16 bool 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 */
36 void 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 
68         uint16_t recordCount = (data[recordCountMSB] << 8) |
69                                data[recordCountLSB];
70 
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 */
78 void 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 */
117 void 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 */
159 void 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 */
205 void 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 */
228     int strAddr = dataLen + ((dataLen / (sdr::perCountByte)) * 4) -
229                   (strLen - 1);
230 
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 */
240 void 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 */
255     int threshold = (sdrDataBytes[sdrtype01::sensorCapability]) &
256                     (sdrThresAccess);
257 
258     /* mData        - 10 bits
259      * mDataByte    - Byte 28 - 8 bits LSB
260      * mTolDataByte - Byte 29 - 2 bits MSB [7-6]
261      */
262     uint16_t mData = ((sdrDataBytes[sdrtype01::mTolDataByte] & 0xC0)
263                       << bitShiftMsb) |
264                      sdrDataBytes[sdrtype01::mDataByte];
265 
266     /* bData        - 10 bits
267      * bDataByte    - Byte 30 - 8 bits LSB
268      * bAcuDataByte - Byte 31 - 2 bits MSB [7-6]
269      */
270     uint16_t bData = ((sdrDataBytes[sdrtype01::bAcuDataByte] & 0xC0)
271                       << bitShiftMsb) |
272                      sdrDataBytes[sdrtype01::bDataByte];
273 
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 */
334 double IpmbSDRDevice::sensorValCalculation(uint16_t mValue, double bValue,
335                                            double expValue, double value)
336 {
337     double sensorValue = ((mValue * value) + bValue) * expValue;
338     return sensorValue;
339 }
340