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 /**
61*524f753fSManojkiran Eda * @brief Ipmb broadcast 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;
761f5b24baSPatrick Williams constexpr ssize_t ipmbMinFrameLength = 7;
771f5b24baSPatrick 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 */
ipmbNetFnLunSet(uint8_t netFn,uint8_t lun)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
ipmbSeqLunSet(uint8_t seq,uint8_t lun)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
ipmbAddressTo7BitSet(uint8_t address)101a642a948SDawid Frycki constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
102a642a948SDawid Frycki {
103a642a948SDawid Frycki return address >> 1;
104a642a948SDawid Frycki }
105a642a948SDawid Frycki
ipmbRespNetFn(uint8_t netFn)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 */
ipmbNetFnGet(uint8_t netFnLun)114a642a948SDawid Frycki constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
115a642a948SDawid Frycki {
116a642a948SDawid Frycki return netFnLun >> 2;
117a642a948SDawid Frycki }
118a642a948SDawid Frycki
ipmbLunFromNetFnLunGet(uint8_t netFnLun)119a642a948SDawid Frycki constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
120a642a948SDawid Frycki {
121a642a948SDawid Frycki return netFnLun & ipmbLunMask;
122a642a948SDawid Frycki }
123a642a948SDawid Frycki
ipmbSeqGet(uint8_t seqNumLun)124a642a948SDawid Frycki constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
125a642a948SDawid Frycki {
126a642a948SDawid Frycki return seqNumLun >> 2;
127a642a948SDawid Frycki }
128a642a948SDawid Frycki
ipmbLunFromSeqLunGet(uint8_t seqNumLun)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 */
ipmbIsResponse(IPMB_HEADER * ipmbHeader)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
ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)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:
2650736e213SMatt Simmering IpmbChannel(boost::asio::io_context& io, uint8_t ipmbBmcTargetAddress,
2660736e213SMatt Simmering uint8_t ipmbRqTargetAddress, 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
2720736e213SMatt Simmering int ipmbChannelInit(const char* ipmbI2cTarget);
273a642a948SDawid Frycki
2740736e213SMatt Simmering int ipmbChannelUpdateTargetAddress(const uint8_t newBmcTargetAddr);
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
2860736e213SMatt Simmering uint8_t getBmcTargetAddress();
287a642a948SDawid Frycki
2880736e213SMatt Simmering uint8_t getRqTargetAddress();
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:
3020736e213SMatt Simmering boost::asio::posix::stream_descriptor i2cTargetDescriptor;
303a642a948SDawid Frycki
3040736e213SMatt Simmering int ipmbi2cTargetFd;
305a642a948SDawid Frycki
3060736e213SMatt Simmering uint8_t ipmbBmcTargetAddress;
3070736e213SMatt Simmering uint8_t ipmbRqTargetAddress;
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:
ioWrite(std::vector<uint8_t> & buffer)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
name()343bbfd00abSQiang XU int name()
344bbfd00abSQiang XU {
345bbfd00abSQiang XU return static_cast<int>(I2C_RDWR);
346bbfd00abSQiang XU }
347bbfd00abSQiang XU
data()348bbfd00abSQiang XU void* data()
349bbfd00abSQiang XU {
350bbfd00abSQiang XU return &msgRdwr;
351bbfd00abSQiang XU }
352bbfd00abSQiang XU
353bbfd00abSQiang XU private:
354f094ab34SPatrick Williams i2c_rdwr_ioctl_data msgRdwr = {};
355f094ab34SPatrick Williams i2c_msg i2cmsg[1] = {};
356bbfd00abSQiang XU };
357bbfd00abSQiang XU
358a642a948SDawid Frycki #endif
359