xref: /openbmc/ipmbbridge/ipmbbridged.hpp (revision 1f5b24baa979dc176a83b069fbc6189a1a623ef0)
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 
181486b8acSEd Tanous #include <boost/asio/io_context.hpp>
1909027c0eSEd Tanous #include <boost/asio/steady_timer.hpp>
20a642a948SDawid Frycki #include <boost/container/flat_set.hpp>
21a642a948SDawid Frycki #include <sdbusplus/asio/object_server.hpp>
22a642a948SDawid Frycki #include <sdbusplus/message.hpp>
23fe0d38a0SPatrick Williams 
24fe0d38a0SPatrick Williams #include <optional>
25a642a948SDawid Frycki #include <vector>
26a642a948SDawid Frycki 
27fe0d38a0SPatrick Williams extern "C"
28fe0d38a0SPatrick Williams {
29bbfd00abSQiang XU #include <i2c/smbus.h>
30bbfd00abSQiang XU #include <linux/i2c-dev.h>
31bbfd00abSQiang XU }
32bbfd00abSQiang XU 
33a642a948SDawid Frycki #ifndef IPMBBRIDGED_HPP
34a642a948SDawid Frycki #define IPMBBRIDGED_HPP
35a642a948SDawid Frycki 
36a642a948SDawid Frycki /**
37a642a948SDawid Frycki  * @brief Ipmb return status codes (sendRequest API call)
38a642a948SDawid Frycki  */
39a642a948SDawid Frycki enum class ipmbResponseStatus
40a642a948SDawid Frycki {
41a642a948SDawid Frycki     success = 0,
42a642a948SDawid Frycki     error = 1,
43a642a948SDawid Frycki     invalid_param = 2,
44a642a948SDawid Frycki     busy = 3,
45a642a948SDawid Frycki     timeout = 4,
46a642a948SDawid Frycki };
47a642a948SDawid Frycki 
48a642a948SDawid Frycki /**
49a642a948SDawid Frycki  * @brief Ipmb outstanding requests defines
50a642a948SDawid Frycki  */
51a642a948SDawid Frycki constexpr int ipmbMaxOutstandingRequestsCount = 64;
52a642a948SDawid Frycki constexpr int ipmbNumberOfTries = 6;
53a642a948SDawid Frycki constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
54a642a948SDawid Frycki 
55a642a948SDawid Frycki /**
56a642a948SDawid Frycki  * @brief Ipmb I2C communication
57a642a948SDawid Frycki  */
58a642a948SDawid Frycki constexpr uint8_t ipmbI2cNumberOfRetries = 2;
59a642a948SDawid Frycki 
60a642a948SDawid Frycki /**
61bbfd00abSQiang XU  * @brief Ipmb boardcast address
62bbfd00abSQiang XU  */
63bbfd00abSQiang XU constexpr uint8_t broadcastAddress = 0x0;
64bbfd00abSQiang XU 
65bbfd00abSQiang XU /**
66a642a948SDawid Frycki  * @brief Ipmb defines
67a642a948SDawid Frycki  */
68a642a948SDawid Frycki constexpr size_t ipmbMaxDataSize = 256;
69a642a948SDawid Frycki constexpr size_t ipmbConnectionHeaderLength = 3;
70a642a948SDawid Frycki constexpr size_t ipmbResponseDataHeaderLength = 4;
71a642a948SDawid Frycki constexpr size_t ipmbRequestDataHeaderLength = 3;
72a642a948SDawid Frycki constexpr size_t ipmbAddressSize = 1;
7337a7eaceSVijay Khemka constexpr size_t ipmbPktLenSize = 1;
74a642a948SDawid Frycki constexpr size_t ipmbChecksumSize = 1;
75a642a948SDawid Frycki constexpr size_t ipmbChecksum2StartOffset = 3;
76*1f5b24baSPatrick Williams constexpr ssize_t ipmbMinFrameLength = 7;
77*1f5b24baSPatrick Williams constexpr ssize_t ipmbMaxFrameLength =
7837a7eaceSVijay Khemka     ipmbPktLenSize + ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength +
79a642a948SDawid Frycki     ipmbChecksumSize + ipmbMaxDataSize;
80a642a948SDawid Frycki 
81a642a948SDawid Frycki /**
82a642a948SDawid Frycki  * @brief Ipmb misc
83a642a948SDawid Frycki  */
84a642a948SDawid Frycki constexpr uint8_t ipmbNetFnResponseMask = 0x01;
85a642a948SDawid Frycki constexpr uint8_t ipmbLunMask = 0x03;
86a642a948SDawid Frycki constexpr uint8_t ipmbRsLun = 0x0;
87a642a948SDawid Frycki 
88a642a948SDawid Frycki /**
89a642a948SDawid Frycki  * @brief Ipmb setters
90a642a948SDawid Frycki  */
91a642a948SDawid Frycki constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
92a642a948SDawid Frycki {
93a642a948SDawid Frycki     return ((netFn << 2) | (lun & ipmbLunMask));
94a642a948SDawid Frycki }
95a642a948SDawid Frycki 
96a642a948SDawid Frycki constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
97a642a948SDawid Frycki {
98a642a948SDawid Frycki     return ((seq << 2) | (lun & ipmbLunMask));
99a642a948SDawid Frycki }
100a642a948SDawid Frycki 
101a642a948SDawid Frycki constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
102a642a948SDawid Frycki {
103a642a948SDawid Frycki     return address >> 1;
104a642a948SDawid Frycki }
105a642a948SDawid Frycki 
106a642a948SDawid Frycki constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
107a642a948SDawid Frycki {
108a642a948SDawid Frycki     return netFn |= 1;
109a642a948SDawid Frycki }
110a642a948SDawid Frycki 
111a642a948SDawid Frycki /**
112a642a948SDawid Frycki  * @brief Ipmb getters
113a642a948SDawid Frycki  */
114a642a948SDawid Frycki constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
115a642a948SDawid Frycki {
116a642a948SDawid Frycki     return netFnLun >> 2;
117a642a948SDawid Frycki }
118a642a948SDawid Frycki 
119a642a948SDawid Frycki constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
120a642a948SDawid Frycki {
121a642a948SDawid Frycki     return netFnLun & ipmbLunMask;
122a642a948SDawid Frycki }
123a642a948SDawid Frycki 
124a642a948SDawid Frycki constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
125a642a948SDawid Frycki {
126a642a948SDawid Frycki     return seqNumLun >> 2;
127a642a948SDawid Frycki }
128a642a948SDawid Frycki 
129a642a948SDawid Frycki constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
130a642a948SDawid Frycki {
131a642a948SDawid Frycki     return seqNumLun & ipmbLunMask;
132a642a948SDawid Frycki }
133a642a948SDawid Frycki 
134a642a948SDawid Frycki /**
135a642a948SDawid Frycki  * @brief Ipmb checkers
136a642a948SDawid Frycki  */
137a642a948SDawid Frycki constexpr bool ipmbIsResponse(IPMB_HEADER* ipmbHeader)
138a642a948SDawid Frycki {
139a642a948SDawid Frycki     return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
140a642a948SDawid Frycki            ipmbNetFnResponseMask;
141a642a948SDawid Frycki }
142a642a948SDawid Frycki 
143a642a948SDawid Frycki /**
144a642a948SDawid Frycki  * @brief Ipmb request state
145a642a948SDawid Frycki  */
146a642a948SDawid Frycki enum class ipmbRequestState
147a642a948SDawid Frycki {
148a642a948SDawid Frycki     invalid,
149a642a948SDawid Frycki     valid,
150a642a948SDawid Frycki     matched,
151a642a948SDawid Frycki };
152a642a948SDawid Frycki 
153a642a948SDawid Frycki /**
154a642a948SDawid Frycki  * @brief Channel types
155a642a948SDawid Frycki  */
156a642a948SDawid Frycki enum class ipmbChannelType
157a642a948SDawid Frycki {
158a642a948SDawid Frycki     ipmb = 0,
159a642a948SDawid Frycki     me = 1
160a642a948SDawid Frycki };
161a642a948SDawid Frycki 
162a642a948SDawid Frycki /**
163a642a948SDawid Frycki  * @brief IpmbResponse declaration
164a642a948SDawid Frycki  */
165a642a948SDawid Frycki struct IpmbResponse
166a642a948SDawid Frycki {
167a642a948SDawid Frycki     uint8_t address;
168a642a948SDawid Frycki     uint8_t netFn;
169a642a948SDawid Frycki     uint8_t rqLun;
170a642a948SDawid Frycki     uint8_t rsSA;
171a642a948SDawid Frycki     uint8_t seq;
172a642a948SDawid Frycki     uint8_t rsLun;
173a642a948SDawid Frycki     uint8_t cmd;
174a642a948SDawid Frycki     uint8_t completionCode;
175a642a948SDawid Frycki     std::vector<uint8_t> data;
176a642a948SDawid Frycki 
177a642a948SDawid Frycki     IpmbResponse();
178a642a948SDawid Frycki 
179a642a948SDawid Frycki     IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
180a642a948SDawid Frycki                  uint8_t seq, uint8_t rsLun, uint8_t cmd,
1818188d765SDawid Frycki                  uint8_t completionCode, const std::vector<uint8_t>& inputData);
182a642a948SDawid Frycki 
183a642a948SDawid Frycki     void i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer, size_t bufferLength);
184a642a948SDawid Frycki 
1858188d765SDawid Frycki     std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct();
186a642a948SDawid Frycki };
187a642a948SDawid Frycki 
188a642a948SDawid Frycki /**
189a642a948SDawid Frycki  * @brief IpmbRequest declaration
190a642a948SDawid Frycki  */
191a642a948SDawid Frycki struct IpmbRequest
192a642a948SDawid Frycki {
193a642a948SDawid Frycki     uint8_t address;
194a642a948SDawid Frycki     uint8_t netFn;
195a642a948SDawid Frycki     uint8_t rsLun;
196a642a948SDawid Frycki     uint8_t rqSA;
197a642a948SDawid Frycki     uint8_t seq;
198a642a948SDawid Frycki     uint8_t rqLun;
199a642a948SDawid Frycki     uint8_t cmd;
200a642a948SDawid Frycki     std::vector<uint8_t> data;
201a642a948SDawid Frycki 
202a642a948SDawid Frycki     size_t dataLength;
203a642a948SDawid Frycki     ipmbRequestState state;
204a642a948SDawid Frycki     std::optional<boost::asio::steady_timer> timer;
205a642a948SDawid Frycki     std::unique_ptr<IpmbResponse> matchedResponse;
206a642a948SDawid Frycki 
207a642a948SDawid Frycki     // creates empty request with empty timer object
208a642a948SDawid Frycki     IpmbRequest();
209a642a948SDawid Frycki 
210a642a948SDawid Frycki     IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
211a642a948SDawid Frycki                 uint8_t seq, uint8_t rqLun, uint8_t cmd,
2128188d765SDawid Frycki                 const std::vector<uint8_t>& inputData);
213a642a948SDawid Frycki 
214a642a948SDawid Frycki     IpmbRequest(const IpmbRequest&) = delete;
215fe0d38a0SPatrick Williams     IpmbRequest& operator=(const IpmbRequest&) = delete;
216a642a948SDawid Frycki 
217a642a948SDawid Frycki     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
218a642a948SDawid Frycki         returnMatchedResponse();
219a642a948SDawid Frycki 
220a642a948SDawid Frycki     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
221a642a948SDawid Frycki         returnStatusResponse(int status);
222a642a948SDawid Frycki 
223a642a948SDawid Frycki     void i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer, size_t bufferLength);
224a642a948SDawid Frycki 
225a642a948SDawid Frycki     int ipmbToi2cConstruct(std::vector<uint8_t>& buffer);
226a642a948SDawid Frycki };
227a642a948SDawid Frycki 
228a642a948SDawid Frycki /**
229a642a948SDawid Frycki  * @brief Command filtering class declaration
230a642a948SDawid Frycki  *
231a642a948SDawid Frycki  * This feature provides simple mechanism for filtering out commands - which are
232a642a948SDawid Frycki  * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
233a642a948SDawid Frycki  */
234a642a948SDawid Frycki class IpmbCommandFilter
235a642a948SDawid Frycki {
236a642a948SDawid Frycki   public:
237a642a948SDawid Frycki     // function checking if netFn & cmd combination exist in blocked command
238a642a948SDawid Frycki     // list
239a642a948SDawid Frycki     bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
240a642a948SDawid Frycki     // function adding netfFn & cmd combination to the blocked command list
241a642a948SDawid Frycki     void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
242a642a948SDawid Frycki 
243a642a948SDawid Frycki   private:
244a642a948SDawid Frycki     boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
245a642a948SDawid Frycki };
246a642a948SDawid Frycki 
247a642a948SDawid Frycki /**
248a642a948SDawid Frycki  * @brief Command filtering defines
249a642a948SDawid Frycki  */
250a642a948SDawid Frycki 
2518188d765SDawid Frycki constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1;
2528188d765SDawid Frycki constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE;
253a642a948SDawid Frycki 
254a642a948SDawid Frycki constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
255a642a948SDawid Frycki {
256a642a948SDawid Frycki     return reqNetFn & ~ipmbNetFnResponseMask;
257a642a948SDawid Frycki }
258a642a948SDawid Frycki 
259a642a948SDawid Frycki /**
260a642a948SDawid Frycki  * @brief IpmbChannel class declaration
261a642a948SDawid Frycki  */
262a642a948SDawid Frycki class IpmbChannel
263a642a948SDawid Frycki {
264a642a948SDawid Frycki   public:
2651486b8acSEd Tanous     IpmbChannel(boost::asio::io_context& io, uint8_t ipmbBmcSlaveAddress,
266950a2e81SKumar Thangavel                 uint8_t ipmbRqSlaveAddress, uint8_t channelIdx,
267a642a948SDawid Frycki                 std::shared_ptr<IpmbCommandFilter> commandFilter);
268a642a948SDawid Frycki 
269a642a948SDawid Frycki     IpmbChannel(const IpmbChannel&) = delete;
270fe0d38a0SPatrick Williams     IpmbChannel& operator=(const IpmbChannel&) = delete;
271a642a948SDawid Frycki 
27237a7eaceSVijay Khemka     int ipmbChannelInit(const char* ipmbI2cSlave);
273a642a948SDawid Frycki 
2748edcf1a0SQiang XU     int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr);
2758edcf1a0SQiang XU 
276a642a948SDawid Frycki     bool seqNumGet(uint8_t& seq);
277a642a948SDawid Frycki 
278a642a948SDawid Frycki     ipmbChannelType getChannelType();
279a642a948SDawid Frycki 
2808edcf1a0SQiang XU     uint8_t getBusId();
2818edcf1a0SQiang XU 
282950a2e81SKumar Thangavel     uint8_t getDevIndex();
283950a2e81SKumar Thangavel 
284950a2e81SKumar Thangavel     uint8_t getChannelIdx();
285950a2e81SKumar Thangavel 
286a642a948SDawid Frycki     uint8_t getBmcSlaveAddress();
287a642a948SDawid Frycki 
288a642a948SDawid Frycki     uint8_t getRqSlaveAddress();
289a642a948SDawid Frycki 
290a642a948SDawid Frycki     void addFilter(const uint8_t respNetFn, const uint8_t cmd);
291a642a948SDawid Frycki 
292a642a948SDawid Frycki     void processI2cEvent();
293a642a948SDawid Frycki 
294bbfd00abSQiang XU     void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
295a642a948SDawid Frycki                           size_t retriesAttempted);
296a642a948SDawid Frycki 
297a642a948SDawid Frycki     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
298a642a948SDawid Frycki         requestAdd(boost::asio::yield_context& yield,
299a642a948SDawid Frycki                    std::shared_ptr<IpmbRequest> requestToSend);
300a642a948SDawid Frycki 
301a642a948SDawid Frycki   private:
30237a7eaceSVijay Khemka     boost::asio::posix::stream_descriptor i2cSlaveDescriptor;
303a642a948SDawid Frycki 
304a642a948SDawid Frycki     int ipmbi2cSlaveFd;
305a642a948SDawid Frycki 
306a642a948SDawid Frycki     uint8_t ipmbBmcSlaveAddress;
307a642a948SDawid Frycki     uint8_t ipmbRqSlaveAddress;
3088edcf1a0SQiang XU     uint8_t ipmbBusId;
309950a2e81SKumar Thangavel     uint8_t channelIdx;
310a642a948SDawid Frycki 
311a642a948SDawid Frycki     std::shared_ptr<IpmbCommandFilter> commandFilter;
312a642a948SDawid Frycki 
313a642a948SDawid Frycki     // array storing outstanding requests
314a642a948SDawid Frycki     std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
315a642a948SDawid Frycki         outstandingRequests;
316a642a948SDawid Frycki 
317a642a948SDawid Frycki     void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
318a642a948SDawid Frycki                               std::shared_ptr<std::vector<uint8_t>> buffer);
319a642a948SDawid Frycki 
320a642a948SDawid Frycki     void responseMatch(std::unique_ptr<IpmbResponse>& response);
321a642a948SDawid Frycki 
322a642a948SDawid Frycki     void makeRequestInvalid(IpmbRequest& request);
323a642a948SDawid Frycki 
324a642a948SDawid Frycki     void makeRequestValid(std::shared_ptr<IpmbRequest> request);
325a642a948SDawid Frycki };
326a642a948SDawid Frycki 
327bbfd00abSQiang XU /**
328bbfd00abSQiang XU  * @brief ioWrite class declaration
329bbfd00abSQiang XU  */
330bbfd00abSQiang XU class ioWrite
331bbfd00abSQiang XU {
332bbfd00abSQiang XU   public:
333bbfd00abSQiang XU     ioWrite(std::vector<uint8_t>& buffer)
334bbfd00abSQiang XU     {
335bbfd00abSQiang XU         i2cmsg[0].addr = ipmbAddressTo7BitSet(buffer[0]);
336bbfd00abSQiang XU         i2cmsg[0].len = buffer.size() - ipmbAddressSize;
337bbfd00abSQiang XU         i2cmsg[0].buf = buffer.data() + ipmbAddressSize;
338bbfd00abSQiang XU 
339bbfd00abSQiang XU         msgRdwr.msgs = i2cmsg;
340bbfd00abSQiang XU         msgRdwr.nmsgs = 1;
341bbfd00abSQiang XU     };
342bbfd00abSQiang XU 
343bbfd00abSQiang XU     int name()
344bbfd00abSQiang XU     {
345bbfd00abSQiang XU         return static_cast<int>(I2C_RDWR);
346bbfd00abSQiang XU     }
347bbfd00abSQiang XU 
348bbfd00abSQiang XU     void* data()
349bbfd00abSQiang XU     {
350bbfd00abSQiang XU         return &msgRdwr;
351bbfd00abSQiang XU     }
352bbfd00abSQiang XU 
353bbfd00abSQiang XU   private:
354bbfd00abSQiang XU     int myname;
355bbfd00abSQiang XU     i2c_rdwr_ioctl_data msgRdwr = {0};
356bbfd00abSQiang XU     i2c_msg i2cmsg[1] = {0};
357bbfd00abSQiang XU };
358bbfd00abSQiang XU 
359a642a948SDawid Frycki #endif
360