blob: b8f708a6d4e21b15d266ad0f877f1a9c039adfa8 [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>
Dawid Fryckia642a942018-06-12 10:44:23 -070021#include <sdbusplus/asio/object_server.hpp>
22#include <sdbusplus/message.hpp>
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050023
24#include <optional>
Dawid Fryckia642a942018-06-12 10:44:23 -070025#include <vector>
26
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050027extern "C"
28{
Qiang XUbbfd00a2019-06-27 21:10:06 +080029#include <i2c/smbus.h>
30#include <linux/i2c-dev.h>
31}
32
Dawid Fryckia642a942018-06-12 10:44:23 -070033#ifndef IPMBBRIDGED_HPP
34#define IPMBBRIDGED_HPP
35
36/**
37 * @brief Ipmb return status codes (sendRequest API call)
38 */
39enum class ipmbResponseStatus
40{
41 success = 0,
42 error = 1,
43 invalid_param = 2,
44 busy = 3,
45 timeout = 4,
46};
47
48/**
49 * @brief Ipmb outstanding requests defines
50 */
51constexpr int ipmbMaxOutstandingRequestsCount = 64;
52constexpr int ipmbNumberOfTries = 6;
53constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
54
55/**
56 * @brief Ipmb I2C communication
57 */
58constexpr uint8_t ipmbI2cNumberOfRetries = 2;
59
60/**
Manojkiran Eda524f7532024-06-17 14:22:24 +053061 * @brief Ipmb broadcast address
Qiang XUbbfd00a2019-06-27 21:10:06 +080062 */
63constexpr uint8_t broadcastAddress = 0x0;
64
65/**
Dawid Fryckia642a942018-06-12 10:44:23 -070066 * @brief Ipmb defines
67 */
68constexpr size_t ipmbMaxDataSize = 256;
69constexpr size_t ipmbConnectionHeaderLength = 3;
70constexpr size_t ipmbResponseDataHeaderLength = 4;
71constexpr size_t ipmbRequestDataHeaderLength = 3;
72constexpr size_t ipmbAddressSize = 1;
Vijay Khemka37a7eac2019-12-06 13:52:28 -080073constexpr size_t ipmbPktLenSize = 1;
Dawid Fryckia642a942018-06-12 10:44:23 -070074constexpr size_t ipmbChecksumSize = 1;
75constexpr size_t ipmbChecksum2StartOffset = 3;
Patrick Williams1f5b24b2023-03-30 15:36:03 -050076constexpr ssize_t ipmbMinFrameLength = 7;
77constexpr ssize_t ipmbMaxFrameLength =
Vijay Khemka37a7eac2019-12-06 13:52:28 -080078 ipmbPktLenSize + ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength +
79 ipmbChecksumSize + ipmbMaxDataSize;
Dawid Fryckia642a942018-06-12 10:44:23 -070080
81/**
82 * @brief Ipmb misc
83 */
84constexpr uint8_t ipmbNetFnResponseMask = 0x01;
85constexpr uint8_t ipmbLunMask = 0x03;
Dawid Fryckia642a942018-06-12 10:44:23 -070086constexpr uint8_t ipmbRsLun = 0x0;
87
88/**
89 * @brief Ipmb setters
90 */
91constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
92{
93 return ((netFn << 2) | (lun & ipmbLunMask));
94}
95
96constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
97{
98 return ((seq << 2) | (lun & ipmbLunMask));
99}
100
101constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
102{
103 return address >> 1;
104}
105
106constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
107{
108 return netFn |= 1;
109}
110
111/**
112 * @brief Ipmb getters
113 */
114constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
115{
116 return netFnLun >> 2;
117}
118
119constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
120{
121 return netFnLun & ipmbLunMask;
122}
123
124constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
125{
126 return seqNumLun >> 2;
127}
128
129constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
130{
131 return seqNumLun & ipmbLunMask;
132}
133
134/**
135 * @brief Ipmb checkers
136 */
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500137constexpr bool ipmbIsResponse(IPMB_HEADER* ipmbHeader)
Dawid Fryckia642a942018-06-12 10:44:23 -0700138{
139 return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
140 ipmbNetFnResponseMask;
141}
142
143/**
144 * @brief Ipmb request state
145 */
146enum class ipmbRequestState
147{
148 invalid,
149 valid,
150 matched,
151};
152
153/**
154 * @brief Channel types
155 */
156enum class ipmbChannelType
157{
158 ipmb = 0,
159 me = 1
160};
161
Dawid Fryckia642a942018-06-12 10:44:23 -0700162/**
163 * @brief IpmbResponse declaration
164 */
165struct IpmbResponse
166{
167 uint8_t address;
168 uint8_t netFn;
169 uint8_t rqLun;
170 uint8_t rsSA;
171 uint8_t seq;
172 uint8_t rsLun;
173 uint8_t cmd;
174 uint8_t completionCode;
175 std::vector<uint8_t> data;
176
177 IpmbResponse();
178
179 IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
180 uint8_t seq, uint8_t rsLun, uint8_t cmd,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500181 uint8_t completionCode, const std::vector<uint8_t>& inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700182
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500183 void i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer, size_t bufferLength);
Dawid Fryckia642a942018-06-12 10:44:23 -0700184
Dawid Frycki8188d762019-04-01 18:03:48 -0700185 std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct();
Dawid Fryckia642a942018-06-12 10:44:23 -0700186};
187
188/**
189 * @brief IpmbRequest declaration
190 */
191struct IpmbRequest
192{
193 uint8_t address;
194 uint8_t netFn;
195 uint8_t rsLun;
196 uint8_t rqSA;
197 uint8_t seq;
198 uint8_t rqLun;
199 uint8_t cmd;
200 std::vector<uint8_t> data;
201
202 size_t dataLength;
203 ipmbRequestState state;
204 std::optional<boost::asio::steady_timer> timer;
205 std::unique_ptr<IpmbResponse> matchedResponse;
206
207 // creates empty request with empty timer object
208 IpmbRequest();
209
210 IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
211 uint8_t seq, uint8_t rqLun, uint8_t cmd,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500212 const std::vector<uint8_t>& inputData);
Dawid Fryckia642a942018-06-12 10:44:23 -0700213
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500214 IpmbRequest(const IpmbRequest&) = delete;
215 IpmbRequest& operator=(const IpmbRequest&) = delete;
Dawid Fryckia642a942018-06-12 10:44:23 -0700216
Dawid Fryckia642a942018-06-12 10:44:23 -0700217 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
218 returnMatchedResponse();
219
220 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
221 returnStatusResponse(int status);
222
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500223 void i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer, size_t bufferLength);
Dawid Fryckia642a942018-06-12 10:44:23 -0700224
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500225 int ipmbToi2cConstruct(std::vector<uint8_t>& buffer);
Dawid Fryckia642a942018-06-12 10:44:23 -0700226};
227
228/**
229 * @brief Command filtering class declaration
230 *
231 * This feature provides simple mechanism for filtering out commands - which are
232 * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
233 */
234class IpmbCommandFilter
235{
236 public:
237 // function checking if netFn & cmd combination exist in blocked command
238 // list
239 bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
240 // function adding netfFn & cmd combination to the blocked command list
241 void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
242
243 private:
244 boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
245};
246
247/**
248 * @brief Command filtering defines
249 */
250
Dawid Frycki8188d762019-04-01 18:03:48 -0700251constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1;
252constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE;
Dawid Fryckia642a942018-06-12 10:44:23 -0700253
254constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
255{
256 return reqNetFn & ~ipmbNetFnResponseMask;
257}
258
259/**
260 * @brief IpmbChannel class declaration
261 */
262class IpmbChannel
263{
264 public:
Matt Simmering0736e212023-11-01 16:28:55 -0700265 IpmbChannel(boost::asio::io_context& io, uint8_t ipmbBmcTargetAddress,
266 uint8_t ipmbRqTargetAddress, uint8_t channelIdx,
Dawid Fryckia642a942018-06-12 10:44:23 -0700267 std::shared_ptr<IpmbCommandFilter> commandFilter);
268
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500269 IpmbChannel(const IpmbChannel&) = delete;
270 IpmbChannel& operator=(const IpmbChannel&) = delete;
Dawid Fryckia642a942018-06-12 10:44:23 -0700271
Matt Simmering0736e212023-11-01 16:28:55 -0700272 int ipmbChannelInit(const char* ipmbI2cTarget);
Dawid Fryckia642a942018-06-12 10:44:23 -0700273
Matt Simmering0736e212023-11-01 16:28:55 -0700274 int ipmbChannelUpdateTargetAddress(const uint8_t newBmcTargetAddr);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800275
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500276 bool seqNumGet(uint8_t& seq);
Dawid Fryckia642a942018-06-12 10:44:23 -0700277
278 ipmbChannelType getChannelType();
279
Qiang XU8edcf1a2019-06-14 22:18:15 +0800280 uint8_t getBusId();
281
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530282 uint8_t getDevIndex();
283
284 uint8_t getChannelIdx();
285
Matt Simmering0736e212023-11-01 16:28:55 -0700286 uint8_t getBmcTargetAddress();
Dawid Fryckia642a942018-06-12 10:44:23 -0700287
Matt Simmering0736e212023-11-01 16:28:55 -0700288 uint8_t getRqTargetAddress();
Dawid Fryckia642a942018-06-12 10:44:23 -0700289
290 void addFilter(const uint8_t respNetFn, const uint8_t cmd);
291
292 void processI2cEvent();
293
Qiang XUbbfd00a2019-06-27 21:10:06 +0800294 void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
Dawid Fryckia642a942018-06-12 10:44:23 -0700295 size_t retriesAttempted);
296
297 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500298 requestAdd(boost::asio::yield_context& yield,
Dawid Fryckia642a942018-06-12 10:44:23 -0700299 std::shared_ptr<IpmbRequest> requestToSend);
300
301 private:
Matt Simmering0736e212023-11-01 16:28:55 -0700302 boost::asio::posix::stream_descriptor i2cTargetDescriptor;
Dawid Fryckia642a942018-06-12 10:44:23 -0700303
Matt Simmering0736e212023-11-01 16:28:55 -0700304 int ipmbi2cTargetFd;
Dawid Fryckia642a942018-06-12 10:44:23 -0700305
Matt Simmering0736e212023-11-01 16:28:55 -0700306 uint8_t ipmbBmcTargetAddress;
307 uint8_t ipmbRqTargetAddress;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800308 uint8_t ipmbBusId;
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530309 uint8_t channelIdx;
Dawid Fryckia642a942018-06-12 10:44:23 -0700310
311 std::shared_ptr<IpmbCommandFilter> commandFilter;
312
313 // array storing outstanding requests
314 std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
315 outstandingRequests;
316
317 void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
318 std::shared_ptr<std::vector<uint8_t>> buffer);
319
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500320 void responseMatch(std::unique_ptr<IpmbResponse>& response);
Dawid Fryckia642a942018-06-12 10:44:23 -0700321
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500322 void makeRequestInvalid(IpmbRequest& request);
Dawid Fryckia642a942018-06-12 10:44:23 -0700323
324 void makeRequestValid(std::shared_ptr<IpmbRequest> request);
325};
326
Qiang XUbbfd00a2019-06-27 21:10:06 +0800327/**
328 * @brief ioWrite class declaration
329 */
330class ioWrite
331{
332 public:
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500333 ioWrite(std::vector<uint8_t>& buffer)
Qiang XUbbfd00a2019-06-27 21:10:06 +0800334 {
335 i2cmsg[0].addr = ipmbAddressTo7BitSet(buffer[0]);
336 i2cmsg[0].len = buffer.size() - ipmbAddressSize;
337 i2cmsg[0].buf = buffer.data() + ipmbAddressSize;
338
339 msgRdwr.msgs = i2cmsg;
340 msgRdwr.nmsgs = 1;
341 };
342
343 int name()
344 {
345 return static_cast<int>(I2C_RDWR);
346 }
347
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500348 void* data()
Qiang XUbbfd00a2019-06-27 21:10:06 +0800349 {
350 return &msgRdwr;
351 }
352
353 private:
Patrick Williamsf094ab32023-03-30 15:59:16 -0500354 i2c_rdwr_ioctl_data msgRdwr = {};
355 i2c_msg i2cmsg[1] = {};
Qiang XUbbfd00a2019-06-27 21:10:06 +0800356};
357
Dawid Fryckia642a942018-06-12 10:44:23 -0700358#endif