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