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