blob: d781e17a2343f8db7555611b2abcf601c6bf2d45 [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;
69constexpr size_t ipmbChecksumSize = 1;
70constexpr size_t ipmbChecksum2StartOffset = 3;
71constexpr size_t ipmbMinFrameLength = 7;
72constexpr size_t ipmbMaxFrameLength = ipmbConnectionHeaderLength +
73 ipmbResponseDataHeaderLength +
74 ipmbChecksumSize + ipmbMaxDataSize;
75
76/**
77 * @brief Ipmb misc
78 */
79constexpr uint8_t ipmbNetFnResponseMask = 0x01;
80constexpr uint8_t ipmbLunMask = 0x03;
81constexpr uint8_t ipmbSeqMask = 0x3F;
82constexpr uint8_t ipmbRsLun = 0x0;
83
84/**
85 * @brief Ipmb setters
86 */
87constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
88{
89 return ((netFn << 2) | (lun & ipmbLunMask));
90}
91
92constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
93{
94 return ((seq << 2) | (lun & ipmbLunMask));
95}
96
97constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
98{
99 return address >> 1;
100}
101
102constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
103{
104 return netFn |= 1;
105}
106
107/**
108 * @brief Ipmb getters
109 */
110constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
111{
112 return netFnLun >> 2;
113}
114
115constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
116{
117 return netFnLun & ipmbLunMask;
118}
119
120constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
121{
122 return seqNumLun >> 2;
123}
124
125constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
126{
127 return seqNumLun & ipmbLunMask;
128}
129
130/**
131 * @brief Ipmb checkers
132 */
133constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader)
134{
135 return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
136 ipmbNetFnResponseMask;
137}
138
139/**
140 * @brief Ipmb request state
141 */
142enum class ipmbRequestState
143{
144 invalid,
145 valid,
146 matched,
147};
148
149/**
150 * @brief Channel types
151 */
152enum class ipmbChannelType
153{
154 ipmb = 0,
155 me = 1
156};
157
Dawid Fryckia642a942018-06-12 10:44:23 -0700158/**
159 * @brief IpmbResponse declaration
160 */
161struct IpmbResponse
162{
163 uint8_t address;
164 uint8_t netFn;
165 uint8_t rqLun;
166 uint8_t rsSA;
167 uint8_t seq;
168 uint8_t rsLun;
169 uint8_t cmd;
170 uint8_t completionCode;
171 std::vector<uint8_t> data;
172
173 IpmbResponse();
174
175 IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
176 uint8_t seq, uint8_t rsLun, uint8_t cmd,
Dawid Frycki8188d762019-04-01 18:03:48 -0700177 uint8_t completionCode, const std::vector<uint8_t> &inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700178
179 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
180
Dawid Frycki8188d762019-04-01 18:03:48 -0700181 std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct();
Dawid Fryckia642a942018-06-12 10:44:23 -0700182};
183
184/**
185 * @brief IpmbRequest declaration
186 */
187struct IpmbRequest
188{
189 uint8_t address;
190 uint8_t netFn;
191 uint8_t rsLun;
192 uint8_t rqSA;
193 uint8_t seq;
194 uint8_t rqLun;
195 uint8_t cmd;
196 std::vector<uint8_t> data;
197
198 size_t dataLength;
199 ipmbRequestState state;
200 std::optional<boost::asio::steady_timer> timer;
201 std::unique_ptr<IpmbResponse> matchedResponse;
202
203 // creates empty request with empty timer object
204 IpmbRequest();
205
206 IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
207 uint8_t seq, uint8_t rqLun, uint8_t cmd,
Dawid Frycki8188d762019-04-01 18:03:48 -0700208 const std::vector<uint8_t> &inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700209
210 IpmbRequest(const IpmbRequest &) = delete;
211 IpmbRequest &operator=(IpmbRequest const &) = delete;
212
Dawid Fryckia642a942018-06-12 10:44:23 -0700213 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
214 returnMatchedResponse();
215
216 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
217 returnStatusResponse(int status);
218
219 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
220
221 int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
Dawid Fryckia642a942018-06-12 10:44:23 -0700222};
223
224/**
225 * @brief Command filtering class declaration
226 *
227 * This feature provides simple mechanism for filtering out commands - which are
228 * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
229 */
230class IpmbCommandFilter
231{
232 public:
233 // function checking if netFn & cmd combination exist in blocked command
234 // list
235 bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
236 // function adding netfFn & cmd combination to the blocked command list
237 void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
238
239 private:
240 boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
241};
242
243/**
244 * @brief Command filtering defines
245 */
246
Dawid Frycki8188d762019-04-01 18:03:48 -0700247constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1;
248constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE;
Dawid Fryckia642a942018-06-12 10:44:23 -0700249
250constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
251{
252 return reqNetFn & ~ipmbNetFnResponseMask;
253}
254
255/**
256 * @brief IpmbChannel class declaration
257 */
258class IpmbChannel
259{
260 public:
261 IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress,
262 uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
263 std::shared_ptr<IpmbCommandFilter> commandFilter);
264
265 IpmbChannel(const IpmbChannel &) = delete;
266 IpmbChannel &operator=(IpmbChannel const &) = delete;
267
268 int ipmbChannelInit(const char *ipmbI2cSlave, const char *ipmbI2cMaster);
269
Qiang XU8edcf1a2019-06-14 22:18:15 +0800270 int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr);
271
Dawid Fryckia642a942018-06-12 10:44:23 -0700272 bool seqNumGet(uint8_t &seq);
273
274 ipmbChannelType getChannelType();
275
Qiang XU8edcf1a2019-06-14 22:18:15 +0800276 uint8_t getBusId();
277
Dawid Fryckia642a942018-06-12 10:44:23 -0700278 uint8_t getBmcSlaveAddress();
279
280 uint8_t getRqSlaveAddress();
281
282 void addFilter(const uint8_t respNetFn, const uint8_t cmd);
283
284 void processI2cEvent();
285
Qiang XUbbfd00a2019-06-27 21:10:06 +0800286 void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
Dawid Fryckia642a942018-06-12 10:44:23 -0700287 size_t retriesAttempted);
288
289 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
290 requestAdd(boost::asio::yield_context &yield,
291 std::shared_ptr<IpmbRequest> requestToSend);
292
293 private:
294 boost::asio::ip::tcp::socket i2cSlaveSocket;
295 boost::asio::posix::stream_descriptor i2cMasterSocket;
296
297 int ipmbi2cMasterFd;
298 int ipmbi2cSlaveFd;
299
300 uint8_t ipmbBmcSlaveAddress;
301 uint8_t ipmbRqSlaveAddress;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800302 uint8_t ipmbBusId;
Dawid Fryckia642a942018-06-12 10:44:23 -0700303
304 ipmbChannelType type;
305
306 std::shared_ptr<IpmbCommandFilter> commandFilter;
307
308 // array storing outstanding requests
309 std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
310 outstandingRequests;
311
312 void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
313 std::shared_ptr<std::vector<uint8_t>> buffer);
314
315 void responseMatch(std::unique_ptr<IpmbResponse> &response);
316
317 void makeRequestInvalid(IpmbRequest &request);
318
319 void makeRequestValid(std::shared_ptr<IpmbRequest> request);
320};
321
Qiang XUbbfd00a2019-06-27 21:10:06 +0800322/**
323 * @brief ioWrite class declaration
324 */
325class ioWrite
326{
327 public:
328 ioWrite(std::vector<uint8_t> &buffer)
329 {
330 i2cmsg[0].addr = ipmbAddressTo7BitSet(buffer[0]);
331 i2cmsg[0].len = buffer.size() - ipmbAddressSize;
332 i2cmsg[0].buf = buffer.data() + ipmbAddressSize;
333
334 msgRdwr.msgs = i2cmsg;
335 msgRdwr.nmsgs = 1;
336 };
337
338 int name()
339 {
340 return static_cast<int>(I2C_RDWR);
341 }
342
343 void *data()
344 {
345 return &msgRdwr;
346 }
347
348 private:
349 int myname;
350 i2c_rdwr_ioctl_data msgRdwr = {0};
351 i2c_msg i2cmsg[1] = {0};
352};
353
Dawid Fryckia642a942018-06-12 10:44:23 -0700354#endif