blob: 01b2f44dd0820344b344e97403cbd65d8757fada [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
24#ifndef IPMBBRIDGED_HPP
25#define IPMBBRIDGED_HPP
26
27/**
28 * @brief Ipmb return status codes (sendRequest API call)
29 */
30enum class ipmbResponseStatus
31{
32 success = 0,
33 error = 1,
34 invalid_param = 2,
35 busy = 3,
36 timeout = 4,
37};
38
39/**
40 * @brief Ipmb outstanding requests defines
41 */
42constexpr int ipmbMaxOutstandingRequestsCount = 64;
43constexpr int ipmbNumberOfTries = 6;
44constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
45
46/**
47 * @brief Ipmb I2C communication
48 */
49constexpr uint8_t ipmbI2cNumberOfRetries = 2;
50
51/**
52 * @brief Ipmb defines
53 */
54constexpr size_t ipmbMaxDataSize = 256;
55constexpr size_t ipmbConnectionHeaderLength = 3;
56constexpr size_t ipmbResponseDataHeaderLength = 4;
57constexpr size_t ipmbRequestDataHeaderLength = 3;
58constexpr size_t ipmbAddressSize = 1;
59constexpr size_t ipmbChecksumSize = 1;
60constexpr size_t ipmbChecksum2StartOffset = 3;
61constexpr size_t ipmbMinFrameLength = 7;
62constexpr size_t ipmbMaxFrameLength = ipmbConnectionHeaderLength +
63 ipmbResponseDataHeaderLength +
64 ipmbChecksumSize + ipmbMaxDataSize;
65
66/**
67 * @brief Ipmb misc
68 */
69constexpr uint8_t ipmbNetFnResponseMask = 0x01;
70constexpr uint8_t ipmbLunMask = 0x03;
71constexpr uint8_t ipmbSeqMask = 0x3F;
72constexpr uint8_t ipmbRsLun = 0x0;
73
74/**
75 * @brief Ipmb setters
76 */
77constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
78{
79 return ((netFn << 2) | (lun & ipmbLunMask));
80}
81
82constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
83{
84 return ((seq << 2) | (lun & ipmbLunMask));
85}
86
87constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
88{
89 return address >> 1;
90}
91
92constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
93{
94 return netFn |= 1;
95}
96
97/**
98 * @brief Ipmb getters
99 */
100constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
101{
102 return netFnLun >> 2;
103}
104
105constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
106{
107 return netFnLun & ipmbLunMask;
108}
109
110constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
111{
112 return seqNumLun >> 2;
113}
114
115constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
116{
117 return seqNumLun & ipmbLunMask;
118}
119
120/**
121 * @brief Ipmb checkers
122 */
123constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader)
124{
125 return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
126 ipmbNetFnResponseMask;
127}
128
129/**
130 * @brief Ipmb request state
131 */
132enum class ipmbRequestState
133{
134 invalid,
135 valid,
136 matched,
137};
138
139/**
140 * @brief Channel types
141 */
142enum class ipmbChannelType
143{
144 ipmb = 0,
145 me = 1
146};
147
Dawid Fryckia642a942018-06-12 10:44:23 -0700148/**
149 * @brief IpmbResponse declaration
150 */
151struct IpmbResponse
152{
153 uint8_t address;
154 uint8_t netFn;
155 uint8_t rqLun;
156 uint8_t rsSA;
157 uint8_t seq;
158 uint8_t rsLun;
159 uint8_t cmd;
160 uint8_t completionCode;
161 std::vector<uint8_t> data;
162
163 IpmbResponse();
164
165 IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
166 uint8_t seq, uint8_t rsLun, uint8_t cmd,
Dawid Frycki8188d762019-04-01 18:03:48 -0700167 uint8_t completionCode, const std::vector<uint8_t> &inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700168
169 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
170
Dawid Frycki8188d762019-04-01 18:03:48 -0700171 std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct();
Dawid Fryckia642a942018-06-12 10:44:23 -0700172};
173
174/**
175 * @brief IpmbRequest declaration
176 */
177struct IpmbRequest
178{
179 uint8_t address;
180 uint8_t netFn;
181 uint8_t rsLun;
182 uint8_t rqSA;
183 uint8_t seq;
184 uint8_t rqLun;
185 uint8_t cmd;
186 std::vector<uint8_t> data;
187
188 size_t dataLength;
189 ipmbRequestState state;
190 std::optional<boost::asio::steady_timer> timer;
191 std::unique_ptr<IpmbResponse> matchedResponse;
192
193 // creates empty request with empty timer object
194 IpmbRequest();
195
196 IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
197 uint8_t seq, uint8_t rqLun, uint8_t cmd,
Dawid Frycki8188d762019-04-01 18:03:48 -0700198 const std::vector<uint8_t> &inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700199
200 IpmbRequest(const IpmbRequest &) = delete;
201 IpmbRequest &operator=(IpmbRequest const &) = delete;
202
Dawid Fryckia642a942018-06-12 10:44:23 -0700203 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
204 returnMatchedResponse();
205
206 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
207 returnStatusResponse(int status);
208
209 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
210
211 int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
Dawid Fryckia642a942018-06-12 10:44:23 -0700212};
213
214/**
215 * @brief Command filtering class declaration
216 *
217 * This feature provides simple mechanism for filtering out commands - which are
218 * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
219 */
220class IpmbCommandFilter
221{
222 public:
223 // function checking if netFn & cmd combination exist in blocked command
224 // list
225 bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
226 // function adding netfFn & cmd combination to the blocked command list
227 void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
228
229 private:
230 boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
231};
232
233/**
234 * @brief Command filtering defines
235 */
236
Dawid Frycki8188d762019-04-01 18:03:48 -0700237constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1;
238constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE;
Dawid Fryckia642a942018-06-12 10:44:23 -0700239
240constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
241{
242 return reqNetFn & ~ipmbNetFnResponseMask;
243}
244
245/**
246 * @brief IpmbChannel class declaration
247 */
248class IpmbChannel
249{
250 public:
251 IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress,
252 uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
253 std::shared_ptr<IpmbCommandFilter> commandFilter);
254
255 IpmbChannel(const IpmbChannel &) = delete;
256 IpmbChannel &operator=(IpmbChannel const &) = delete;
257
258 int ipmbChannelInit(const char *ipmbI2cSlave, const char *ipmbI2cMaster);
259
Qiang XU8edcf1a2019-06-14 22:18:15 +0800260 int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr);
261
Dawid Fryckia642a942018-06-12 10:44:23 -0700262 bool seqNumGet(uint8_t &seq);
263
264 ipmbChannelType getChannelType();
265
Qiang XU8edcf1a2019-06-14 22:18:15 +0800266 uint8_t getBusId();
267
Dawid Fryckia642a942018-06-12 10:44:23 -0700268 uint8_t getBmcSlaveAddress();
269
270 uint8_t getRqSlaveAddress();
271
272 void addFilter(const uint8_t respNetFn, const uint8_t cmd);
273
274 void processI2cEvent();
275
276 void ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
277 size_t retriesAttempted);
278
279 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
280 requestAdd(boost::asio::yield_context &yield,
281 std::shared_ptr<IpmbRequest> requestToSend);
282
283 private:
284 boost::asio::ip::tcp::socket i2cSlaveSocket;
285 boost::asio::posix::stream_descriptor i2cMasterSocket;
286
287 int ipmbi2cMasterFd;
288 int ipmbi2cSlaveFd;
289
290 uint8_t ipmbBmcSlaveAddress;
291 uint8_t ipmbRqSlaveAddress;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800292 uint8_t ipmbBusId;
Dawid Fryckia642a942018-06-12 10:44:23 -0700293
294 ipmbChannelType type;
295
296 std::shared_ptr<IpmbCommandFilter> commandFilter;
297
298 // array storing outstanding requests
299 std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
300 outstandingRequests;
301
302 void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
303 std::shared_ptr<std::vector<uint8_t>> buffer);
304
305 void responseMatch(std::unique_ptr<IpmbResponse> &response);
306
307 void makeRequestInvalid(IpmbRequest &request);
308
309 void makeRequestValid(std::shared_ptr<IpmbRequest> request);
310};
311
312#endif