blob: f13ec8f841335022c5d7649251ae0a60740933fa [file] [log] [blame]
Dawid Fryckia642a942018-06-12 10:44:23 -07001/* Copyright 2018 Intel
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ipmbdefines.hpp"
17
Ed Tanous1486b8a2023-02-28 13:28:59 -080018#include <boost/asio/io_context.hpp>
Ed Tanous09027c02020-08-31 17:28:36 -070019#include <boost/asio/steady_timer.hpp>
Dawid Fryckia642a942018-06-12 10:44:23 -070020#include <boost/container/flat_set.hpp>
21#include <optional>
22#include <sdbusplus/asio/object_server.hpp>
23#include <sdbusplus/message.hpp>
24#include <vector>
25
Qiang XUbbfd00a2019-06-27 21:10:06 +080026extern "C" {
27#include <i2c/smbus.h>
28#include <linux/i2c-dev.h>
29}
30
Dawid Fryckia642a942018-06-12 10:44:23 -070031#ifndef IPMBBRIDGED_HPP
32#define IPMBBRIDGED_HPP
33
34/**
35 * @brief Ipmb return status codes (sendRequest API call)
36 */
37enum class ipmbResponseStatus
38{
39 success = 0,
40 error = 1,
41 invalid_param = 2,
42 busy = 3,
43 timeout = 4,
44};
45
46/**
47 * @brief Ipmb outstanding requests defines
48 */
49constexpr int ipmbMaxOutstandingRequestsCount = 64;
50constexpr int ipmbNumberOfTries = 6;
51constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
52
53/**
54 * @brief Ipmb I2C communication
55 */
56constexpr uint8_t ipmbI2cNumberOfRetries = 2;
57
58/**
Qiang XUbbfd00a2019-06-27 21:10:06 +080059 * @brief Ipmb boardcast address
60 */
61constexpr uint8_t broadcastAddress = 0x0;
62
63/**
Dawid Fryckia642a942018-06-12 10:44:23 -070064 * @brief Ipmb defines
65 */
66constexpr size_t ipmbMaxDataSize = 256;
67constexpr size_t ipmbConnectionHeaderLength = 3;
68constexpr size_t ipmbResponseDataHeaderLength = 4;
69constexpr size_t ipmbRequestDataHeaderLength = 3;
70constexpr size_t ipmbAddressSize = 1;
Vijay Khemka37a7eac2019-12-06 13:52:28 -080071constexpr size_t ipmbPktLenSize = 1;
Dawid Fryckia642a942018-06-12 10:44:23 -070072constexpr size_t ipmbChecksumSize = 1;
73constexpr size_t ipmbChecksum2StartOffset = 3;
74constexpr size_t ipmbMinFrameLength = 7;
Vijay Khemka37a7eac2019-12-06 13:52:28 -080075constexpr size_t ipmbMaxFrameLength =
76 ipmbPktLenSize + ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength +
77 ipmbChecksumSize + ipmbMaxDataSize;
Dawid Fryckia642a942018-06-12 10:44:23 -070078
79/**
80 * @brief Ipmb misc
81 */
82constexpr uint8_t ipmbNetFnResponseMask = 0x01;
83constexpr uint8_t ipmbLunMask = 0x03;
84constexpr uint8_t ipmbSeqMask = 0x3F;
85constexpr uint8_t ipmbRsLun = 0x0;
86
87/**
88 * @brief Ipmb setters
89 */
90constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
91{
92 return ((netFn << 2) | (lun & ipmbLunMask));
93}
94
95constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
96{
97 return ((seq << 2) | (lun & ipmbLunMask));
98}
99
100constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
101{
102 return address >> 1;
103}
104
105constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
106{
107 return netFn |= 1;
108}
109
110/**
111 * @brief Ipmb getters
112 */
113constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
114{
115 return netFnLun >> 2;
116}
117
118constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
119{
120 return netFnLun & ipmbLunMask;
121}
122
123constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
124{
125 return seqNumLun >> 2;
126}
127
128constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
129{
130 return seqNumLun & ipmbLunMask;
131}
132
133/**
134 * @brief Ipmb checkers
135 */
136constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader)
137{
138 return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
139 ipmbNetFnResponseMask;
140}
141
142/**
143 * @brief Ipmb request state
144 */
145enum class ipmbRequestState
146{
147 invalid,
148 valid,
149 matched,
150};
151
152/**
153 * @brief Channel types
154 */
155enum class ipmbChannelType
156{
157 ipmb = 0,
158 me = 1
159};
160
Dawid Fryckia642a942018-06-12 10:44:23 -0700161/**
162 * @brief IpmbResponse declaration
163 */
164struct IpmbResponse
165{
166 uint8_t address;
167 uint8_t netFn;
168 uint8_t rqLun;
169 uint8_t rsSA;
170 uint8_t seq;
171 uint8_t rsLun;
172 uint8_t cmd;
173 uint8_t completionCode;
174 std::vector<uint8_t> data;
175
176 IpmbResponse();
177
178 IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
179 uint8_t seq, uint8_t rsLun, uint8_t cmd,
Dawid Frycki8188d762019-04-01 18:03:48 -0700180 uint8_t completionCode, const std::vector<uint8_t> &inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700181
182 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
183
Dawid Frycki8188d762019-04-01 18:03:48 -0700184 std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct();
Dawid Fryckia642a942018-06-12 10:44:23 -0700185};
186
187/**
188 * @brief IpmbRequest declaration
189 */
190struct IpmbRequest
191{
192 uint8_t address;
193 uint8_t netFn;
194 uint8_t rsLun;
195 uint8_t rqSA;
196 uint8_t seq;
197 uint8_t rqLun;
198 uint8_t cmd;
199 std::vector<uint8_t> data;
200
201 size_t dataLength;
202 ipmbRequestState state;
203 std::optional<boost::asio::steady_timer> timer;
204 std::unique_ptr<IpmbResponse> matchedResponse;
205
206 // creates empty request with empty timer object
207 IpmbRequest();
208
209 IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
210 uint8_t seq, uint8_t rqLun, uint8_t cmd,
Dawid Frycki8188d762019-04-01 18:03:48 -0700211 const std::vector<uint8_t> &inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700212
213 IpmbRequest(const IpmbRequest &) = delete;
214 IpmbRequest &operator=(IpmbRequest const &) = delete;
215
Dawid Fryckia642a942018-06-12 10:44:23 -0700216 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
217 returnMatchedResponse();
218
219 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
220 returnStatusResponse(int status);
221
222 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
223
224 int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
Dawid Fryckia642a942018-06-12 10:44:23 -0700225};
226
227/**
228 * @brief Command filtering class declaration
229 *
230 * This feature provides simple mechanism for filtering out commands - which are
231 * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
232 */
233class IpmbCommandFilter
234{
235 public:
236 // function checking if netFn & cmd combination exist in blocked command
237 // list
238 bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
239 // function adding netfFn & cmd combination to the blocked command list
240 void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
241
242 private:
243 boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
244};
245
246/**
247 * @brief Command filtering defines
248 */
249
Dawid Frycki8188d762019-04-01 18:03:48 -0700250constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1;
251constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE;
Dawid Fryckia642a942018-06-12 10:44:23 -0700252
253constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
254{
255 return reqNetFn & ~ipmbNetFnResponseMask;
256}
257
258/**
259 * @brief IpmbChannel class declaration
260 */
261class IpmbChannel
262{
263 public:
Ed Tanous1486b8a2023-02-28 13:28:59 -0800264 IpmbChannel(boost::asio::io_context &io, uint8_t ipmbBmcSlaveAddress,
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530265 uint8_t ipmbRqSlaveAddress, uint8_t channelIdx,
Dawid Fryckia642a942018-06-12 10:44:23 -0700266 std::shared_ptr<IpmbCommandFilter> commandFilter);
267
268 IpmbChannel(const IpmbChannel &) = delete;
269 IpmbChannel &operator=(IpmbChannel const &) = delete;
270
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800271 int ipmbChannelInit(const char *ipmbI2cSlave);
Dawid Fryckia642a942018-06-12 10:44:23 -0700272
Qiang XU8edcf1a2019-06-14 22:18:15 +0800273 int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr);
274
Dawid Fryckia642a942018-06-12 10:44:23 -0700275 bool seqNumGet(uint8_t &seq);
276
277 ipmbChannelType getChannelType();
278
Qiang XU8edcf1a2019-06-14 22:18:15 +0800279 uint8_t getBusId();
280
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530281 uint8_t getDevIndex();
282
283 uint8_t getChannelIdx();
284
Dawid Fryckia642a942018-06-12 10:44:23 -0700285 uint8_t getBmcSlaveAddress();
286
287 uint8_t getRqSlaveAddress();
288
289 void addFilter(const uint8_t respNetFn, const uint8_t cmd);
290
291 void processI2cEvent();
292
Qiang XUbbfd00a2019-06-27 21:10:06 +0800293 void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
Dawid Fryckia642a942018-06-12 10:44:23 -0700294 size_t retriesAttempted);
295
296 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
297 requestAdd(boost::asio::yield_context &yield,
298 std::shared_ptr<IpmbRequest> requestToSend);
299
300 private:
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800301 boost::asio::posix::stream_descriptor i2cSlaveDescriptor;
Dawid Fryckia642a942018-06-12 10:44:23 -0700302
Dawid Fryckia642a942018-06-12 10:44:23 -0700303 int ipmbi2cSlaveFd;
304
305 uint8_t ipmbBmcSlaveAddress;
306 uint8_t ipmbRqSlaveAddress;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800307 uint8_t ipmbBusId;
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530308 uint8_t channelIdx;
Dawid Fryckia642a942018-06-12 10:44:23 -0700309
310 std::shared_ptr<IpmbCommandFilter> commandFilter;
311
312 // array storing outstanding requests
313 std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
314 outstandingRequests;
315
316 void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
317 std::shared_ptr<std::vector<uint8_t>> buffer);
318
319 void responseMatch(std::unique_ptr<IpmbResponse> &response);
320
321 void makeRequestInvalid(IpmbRequest &request);
322
323 void makeRequestValid(std::shared_ptr<IpmbRequest> request);
324};
325
Qiang XUbbfd00a2019-06-27 21:10:06 +0800326/**
327 * @brief ioWrite class declaration
328 */
329class ioWrite
330{
331 public:
332 ioWrite(std::vector<uint8_t> &buffer)
333 {
334 i2cmsg[0].addr = ipmbAddressTo7BitSet(buffer[0]);
335 i2cmsg[0].len = buffer.size() - ipmbAddressSize;
336 i2cmsg[0].buf = buffer.data() + ipmbAddressSize;
337
338 msgRdwr.msgs = i2cmsg;
339 msgRdwr.nmsgs = 1;
340 };
341
342 int name()
343 {
344 return static_cast<int>(I2C_RDWR);
345 }
346
347 void *data()
348 {
349 return &msgRdwr;
350 }
351
352 private:
353 int myname;
354 i2c_rdwr_ioctl_data msgRdwr = {0};
355 i2c_msg i2cmsg[1] = {0};
356};
357
Dawid Fryckia642a942018-06-12 10:44:23 -0700358#endif