blob: e26419540d1ae51976f6441dbe1ab74d6c115642 [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
18#include <boost/container/flat_set.hpp>
19#include <optional>
20#include <sdbusplus/asio/object_server.hpp>
21#include <sdbusplus/message.hpp>
22#include <vector>
23
Qiang XUbbfd00a2019-06-27 21:10:06 +080024extern "C" {
25#include <i2c/smbus.h>
26#include <linux/i2c-dev.h>
27}
28
Dawid Fryckia642a942018-06-12 10:44:23 -070029#ifndef IPMBBRIDGED_HPP
30#define IPMBBRIDGED_HPP
31
32/**
33 * @brief Ipmb return status codes (sendRequest API call)
34 */
35enum class ipmbResponseStatus
36{
37 success = 0,
38 error = 1,
39 invalid_param = 2,
40 busy = 3,
41 timeout = 4,
42};
43
44/**
45 * @brief Ipmb outstanding requests defines
46 */
47constexpr int ipmbMaxOutstandingRequestsCount = 64;
48constexpr int ipmbNumberOfTries = 6;
49constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
50
51/**
52 * @brief Ipmb I2C communication
53 */
54constexpr uint8_t ipmbI2cNumberOfRetries = 2;
55
56/**
Qiang XUbbfd00a2019-06-27 21:10:06 +080057 * @brief Ipmb boardcast address
58 */
59constexpr uint8_t broadcastAddress = 0x0;
60
61/**
Dawid Fryckia642a942018-06-12 10:44:23 -070062 * @brief Ipmb defines
63 */
64constexpr size_t ipmbMaxDataSize = 256;
65constexpr size_t ipmbConnectionHeaderLength = 3;
66constexpr size_t ipmbResponseDataHeaderLength = 4;
67constexpr size_t ipmbRequestDataHeaderLength = 3;
68constexpr size_t ipmbAddressSize = 1;
Vijay Khemka37a7eac2019-12-06 13:52:28 -080069constexpr size_t ipmbPktLenSize = 1;
Dawid Fryckia642a942018-06-12 10:44:23 -070070constexpr size_t ipmbChecksumSize = 1;
71constexpr size_t ipmbChecksum2StartOffset = 3;
72constexpr size_t ipmbMinFrameLength = 7;
Vijay Khemka37a7eac2019-12-06 13:52:28 -080073constexpr size_t ipmbMaxFrameLength =
74 ipmbPktLenSize + ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength +
75 ipmbChecksumSize + ipmbMaxDataSize;
Dawid Fryckia642a942018-06-12 10:44:23 -070076
77/**
78 * @brief Ipmb misc
79 */
80constexpr uint8_t ipmbNetFnResponseMask = 0x01;
81constexpr uint8_t ipmbLunMask = 0x03;
82constexpr uint8_t ipmbSeqMask = 0x3F;
83constexpr uint8_t ipmbRsLun = 0x0;
84
85/**
86 * @brief Ipmb setters
87 */
88constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
89{
90 return ((netFn << 2) | (lun & ipmbLunMask));
91}
92
93constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
94{
95 return ((seq << 2) | (lun & ipmbLunMask));
96}
97
98constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
99{
100 return address >> 1;
101}
102
103constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
104{
105 return netFn |= 1;
106}
107
108/**
109 * @brief Ipmb getters
110 */
111constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
112{
113 return netFnLun >> 2;
114}
115
116constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
117{
118 return netFnLun & ipmbLunMask;
119}
120
121constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
122{
123 return seqNumLun >> 2;
124}
125
126constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
127{
128 return seqNumLun & ipmbLunMask;
129}
130
131/**
132 * @brief Ipmb checkers
133 */
134constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader)
135{
136 return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
137 ipmbNetFnResponseMask;
138}
139
140/**
141 * @brief Ipmb request state
142 */
143enum class ipmbRequestState
144{
145 invalid,
146 valid,
147 matched,
148};
149
150/**
151 * @brief Channel types
152 */
153enum class ipmbChannelType
154{
155 ipmb = 0,
156 me = 1
157};
158
Dawid Fryckia642a942018-06-12 10:44:23 -0700159/**
160 * @brief IpmbResponse declaration
161 */
162struct IpmbResponse
163{
164 uint8_t address;
165 uint8_t netFn;
166 uint8_t rqLun;
167 uint8_t rsSA;
168 uint8_t seq;
169 uint8_t rsLun;
170 uint8_t cmd;
171 uint8_t completionCode;
172 std::vector<uint8_t> data;
173
174 IpmbResponse();
175
176 IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
177 uint8_t seq, uint8_t rsLun, uint8_t cmd,
Dawid Frycki8188d762019-04-01 18:03:48 -0700178 uint8_t completionCode, const std::vector<uint8_t> &inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700179
180 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
181
Dawid Frycki8188d762019-04-01 18:03:48 -0700182 std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct();
Dawid Fryckia642a942018-06-12 10:44:23 -0700183};
184
185/**
186 * @brief IpmbRequest declaration
187 */
188struct IpmbRequest
189{
190 uint8_t address;
191 uint8_t netFn;
192 uint8_t rsLun;
193 uint8_t rqSA;
194 uint8_t seq;
195 uint8_t rqLun;
196 uint8_t cmd;
197 std::vector<uint8_t> data;
198
199 size_t dataLength;
200 ipmbRequestState state;
201 std::optional<boost::asio::steady_timer> timer;
202 std::unique_ptr<IpmbResponse> matchedResponse;
203
204 // creates empty request with empty timer object
205 IpmbRequest();
206
207 IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
208 uint8_t seq, uint8_t rqLun, uint8_t cmd,
Dawid Frycki8188d762019-04-01 18:03:48 -0700209 const std::vector<uint8_t> &inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700210
211 IpmbRequest(const IpmbRequest &) = delete;
212 IpmbRequest &operator=(IpmbRequest const &) = delete;
213
Dawid Fryckia642a942018-06-12 10:44:23 -0700214 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
215 returnMatchedResponse();
216
217 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
218 returnStatusResponse(int status);
219
220 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
221
222 int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
Dawid Fryckia642a942018-06-12 10:44:23 -0700223};
224
225/**
226 * @brief Command filtering class declaration
227 *
228 * This feature provides simple mechanism for filtering out commands - which are
229 * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
230 */
231class IpmbCommandFilter
232{
233 public:
234 // function checking if netFn & cmd combination exist in blocked command
235 // list
236 bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
237 // function adding netfFn & cmd combination to the blocked command list
238 void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
239
240 private:
241 boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
242};
243
244/**
245 * @brief Command filtering defines
246 */
247
Dawid Frycki8188d762019-04-01 18:03:48 -0700248constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1;
249constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE;
Dawid Fryckia642a942018-06-12 10:44:23 -0700250
251constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
252{
253 return reqNetFn & ~ipmbNetFnResponseMask;
254}
255
256/**
257 * @brief IpmbChannel class declaration
258 */
259class IpmbChannel
260{
261 public:
262 IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress,
263 uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
264 std::shared_ptr<IpmbCommandFilter> commandFilter);
265
266 IpmbChannel(const IpmbChannel &) = delete;
267 IpmbChannel &operator=(IpmbChannel const &) = delete;
268
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800269 int ipmbChannelInit(const char *ipmbI2cSlave);
Dawid Fryckia642a942018-06-12 10:44:23 -0700270
Qiang XU8edcf1a2019-06-14 22:18:15 +0800271 int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr);
272
Dawid Fryckia642a942018-06-12 10:44:23 -0700273 bool seqNumGet(uint8_t &seq);
274
275 ipmbChannelType getChannelType();
276
Qiang XU8edcf1a2019-06-14 22:18:15 +0800277 uint8_t getBusId();
278
Dawid Fryckia642a942018-06-12 10:44:23 -0700279 uint8_t getBmcSlaveAddress();
280
281 uint8_t getRqSlaveAddress();
282
283 void addFilter(const uint8_t respNetFn, const uint8_t cmd);
284
285 void processI2cEvent();
286
Qiang XUbbfd00a2019-06-27 21:10:06 +0800287 void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
Dawid Fryckia642a942018-06-12 10:44:23 -0700288 size_t retriesAttempted);
289
290 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
291 requestAdd(boost::asio::yield_context &yield,
292 std::shared_ptr<IpmbRequest> requestToSend);
293
294 private:
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800295 boost::asio::posix::stream_descriptor i2cSlaveDescriptor;
Dawid Fryckia642a942018-06-12 10:44:23 -0700296
Dawid Fryckia642a942018-06-12 10:44:23 -0700297 int ipmbi2cSlaveFd;
298
299 uint8_t ipmbBmcSlaveAddress;
300 uint8_t ipmbRqSlaveAddress;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800301 uint8_t ipmbBusId;
Dawid Fryckia642a942018-06-12 10:44:23 -0700302
303 ipmbChannelType type;
304
305 std::shared_ptr<IpmbCommandFilter> commandFilter;
306
307 // array storing outstanding requests
308 std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
309 outstandingRequests;
310
311 void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
312 std::shared_ptr<std::vector<uint8_t>> buffer);
313
314 void responseMatch(std::unique_ptr<IpmbResponse> &response);
315
316 void makeRequestInvalid(IpmbRequest &request);
317
318 void makeRequestValid(std::shared_ptr<IpmbRequest> request);
319};
320
Qiang XUbbfd00a2019-06-27 21:10:06 +0800321/**
322 * @brief ioWrite class declaration
323 */
324class ioWrite
325{
326 public:
327 ioWrite(std::vector<uint8_t> &buffer)
328 {
329 i2cmsg[0].addr = ipmbAddressTo7BitSet(buffer[0]);
330 i2cmsg[0].len = buffer.size() - ipmbAddressSize;
331 i2cmsg[0].buf = buffer.data() + ipmbAddressSize;
332
333 msgRdwr.msgs = i2cmsg;
334 msgRdwr.nmsgs = 1;
335 };
336
337 int name()
338 {
339 return static_cast<int>(I2C_RDWR);
340 }
341
342 void *data()
343 {
344 return &msgRdwr;
345 }
346
347 private:
348 int myname;
349 i2c_rdwr_ioctl_data msgRdwr = {0};
350 i2c_msg i2cmsg[1] = {0};
351};
352
Dawid Fryckia642a942018-06-12 10:44:23 -0700353#endif