xref: /openbmc/ipmbbridge/ipmbbridged.hpp (revision 8edcf1a0)
1 /* 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 
18 #include <boost/container/flat_set.hpp>
19 #include <optional>
20 #include <sdbusplus/asio/object_server.hpp>
21 #include <sdbusplus/message.hpp>
22 #include <vector>
23 
24 #ifndef IPMBBRIDGED_HPP
25 #define IPMBBRIDGED_HPP
26 
27 /**
28  * @brief Ipmb return status codes (sendRequest API call)
29  */
30 enum class ipmbResponseStatus
31 {
32     success = 0,
33     error = 1,
34     invalid_param = 2,
35     busy = 3,
36     timeout = 4,
37 };
38 
39 /**
40  * @brief Ipmb outstanding requests defines
41  */
42 constexpr int ipmbMaxOutstandingRequestsCount = 64;
43 constexpr int ipmbNumberOfTries = 6;
44 constexpr uint64_t ipmbRequestRetryTimeout = 250; // ms
45 
46 /**
47  * @brief Ipmb I2C communication
48  */
49 constexpr uint8_t ipmbI2cNumberOfRetries = 2;
50 
51 /**
52  * @brief Ipmb defines
53  */
54 constexpr size_t ipmbMaxDataSize = 256;
55 constexpr size_t ipmbConnectionHeaderLength = 3;
56 constexpr size_t ipmbResponseDataHeaderLength = 4;
57 constexpr size_t ipmbRequestDataHeaderLength = 3;
58 constexpr size_t ipmbAddressSize = 1;
59 constexpr size_t ipmbChecksumSize = 1;
60 constexpr size_t ipmbChecksum2StartOffset = 3;
61 constexpr size_t ipmbMinFrameLength = 7;
62 constexpr size_t ipmbMaxFrameLength = ipmbConnectionHeaderLength +
63                                       ipmbResponseDataHeaderLength +
64                                       ipmbChecksumSize + ipmbMaxDataSize;
65 
66 /**
67  * @brief Ipmb misc
68  */
69 constexpr uint8_t ipmbNetFnResponseMask = 0x01;
70 constexpr uint8_t ipmbLunMask = 0x03;
71 constexpr uint8_t ipmbSeqMask = 0x3F;
72 constexpr uint8_t ipmbRsLun = 0x0;
73 
74 /**
75  * @brief Ipmb setters
76  */
77 constexpr uint8_t ipmbNetFnLunSet(uint8_t netFn, uint8_t lun)
78 {
79     return ((netFn << 2) | (lun & ipmbLunMask));
80 }
81 
82 constexpr uint8_t ipmbSeqLunSet(uint8_t seq, uint8_t lun)
83 {
84     return ((seq << 2) | (lun & ipmbLunMask));
85 }
86 
87 constexpr uint8_t ipmbAddressTo7BitSet(uint8_t address)
88 {
89     return address >> 1;
90 }
91 
92 constexpr uint8_t ipmbRespNetFn(uint8_t netFn)
93 {
94     return netFn |= 1;
95 }
96 
97 /**
98  * @brief Ipmb getters
99  */
100 constexpr uint8_t ipmbNetFnGet(uint8_t netFnLun)
101 {
102     return netFnLun >> 2;
103 }
104 
105 constexpr uint8_t ipmbLunFromNetFnLunGet(uint8_t netFnLun)
106 {
107     return netFnLun & ipmbLunMask;
108 }
109 
110 constexpr uint8_t ipmbSeqGet(uint8_t seqNumLun)
111 {
112     return seqNumLun >> 2;
113 }
114 
115 constexpr uint8_t ipmbLunFromSeqLunGet(uint8_t seqNumLun)
116 {
117     return seqNumLun & ipmbLunMask;
118 }
119 
120 /**
121  * @brief Ipmb checkers
122  */
123 constexpr bool ipmbIsResponse(IPMB_HEADER *ipmbHeader)
124 {
125     return ipmbNetFnGet(ipmbHeader->Header.Resp.rqNetFnLUN) &
126            ipmbNetFnResponseMask;
127 }
128 
129 /**
130  * @brief Ipmb request state
131  */
132 enum class ipmbRequestState
133 {
134     invalid,
135     valid,
136     matched,
137 };
138 
139 /**
140  * @brief Channel types
141  */
142 enum class ipmbChannelType
143 {
144     ipmb = 0,
145     me = 1
146 };
147 
148 /**
149  * @brief IpmbResponse declaration
150  */
151 struct IpmbResponse
152 {
153     uint8_t address;
154     uint8_t netFn;
155     uint8_t rqLun;
156     uint8_t rsSA;
157     uint8_t seq;
158     uint8_t rsLun;
159     uint8_t cmd;
160     uint8_t completionCode;
161     std::vector<uint8_t> data;
162 
163     IpmbResponse();
164 
165     IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA,
166                  uint8_t seq, uint8_t rsLun, uint8_t cmd,
167                  uint8_t completionCode, const std::vector<uint8_t> &inputData);
168 
169     void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
170 
171     std::shared_ptr<std::vector<uint8_t>> ipmbToi2cConstruct();
172 };
173 
174 /**
175  * @brief IpmbRequest declaration
176  */
177 struct IpmbRequest
178 {
179     uint8_t address;
180     uint8_t netFn;
181     uint8_t rsLun;
182     uint8_t rqSA;
183     uint8_t seq;
184     uint8_t rqLun;
185     uint8_t cmd;
186     std::vector<uint8_t> data;
187 
188     size_t dataLength;
189     ipmbRequestState state;
190     std::optional<boost::asio::steady_timer> timer;
191     std::unique_ptr<IpmbResponse> matchedResponse;
192 
193     // creates empty request with empty timer object
194     IpmbRequest();
195 
196     IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA,
197                 uint8_t seq, uint8_t rqLun, uint8_t cmd,
198                 const std::vector<uint8_t> &inputData);
199 
200     IpmbRequest(const IpmbRequest &) = delete;
201     IpmbRequest &operator=(IpmbRequest const &) = delete;
202 
203     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
204         returnMatchedResponse();
205 
206     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
207         returnStatusResponse(int status);
208 
209     void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength);
210 
211     int ipmbToi2cConstruct(std::vector<uint8_t> &buffer);
212 };
213 
214 /**
215  * @brief Command filtering class declaration
216  *
217  * This feature provides simple mechanism for filtering out commands - which are
218  * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic
219  */
220 class IpmbCommandFilter
221 {
222   public:
223     // function checking if netFn & cmd combination exist in blocked command
224     // list
225     bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd);
226     // function adding netfFn & cmd combination to the blocked command list
227     void addFilter(const uint8_t reqNetFn, const uint8_t cmd);
228 
229   private:
230     boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands;
231 };
232 
233 /**
234  * @brief Command filtering defines
235  */
236 
237 constexpr uint8_t ipmbIpmiInvalidCmd = 0xC1;
238 constexpr uint8_t ipmbIpmiCmdRespNotProvided = 0xCE;
239 
240 constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn)
241 {
242     return reqNetFn & ~ipmbNetFnResponseMask;
243 }
244 
245 /**
246  * @brief IpmbChannel class declaration
247  */
248 class IpmbChannel
249 {
250   public:
251     IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress,
252                 uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
253                 std::shared_ptr<IpmbCommandFilter> commandFilter);
254 
255     IpmbChannel(const IpmbChannel &) = delete;
256     IpmbChannel &operator=(IpmbChannel const &) = delete;
257 
258     int ipmbChannelInit(const char *ipmbI2cSlave, const char *ipmbI2cMaster);
259 
260     int ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr);
261 
262     bool seqNumGet(uint8_t &seq);
263 
264     ipmbChannelType getChannelType();
265 
266     uint8_t getBusId();
267 
268     uint8_t getBmcSlaveAddress();
269 
270     uint8_t getRqSlaveAddress();
271 
272     void addFilter(const uint8_t respNetFn, const uint8_t cmd);
273 
274     void processI2cEvent();
275 
276     void ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
277                           size_t retriesAttempted);
278 
279     std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
280         requestAdd(boost::asio::yield_context &yield,
281                    std::shared_ptr<IpmbRequest> requestToSend);
282 
283   private:
284     boost::asio::ip::tcp::socket i2cSlaveSocket;
285     boost::asio::posix::stream_descriptor i2cMasterSocket;
286 
287     int ipmbi2cMasterFd;
288     int ipmbi2cSlaveFd;
289 
290     uint8_t ipmbBmcSlaveAddress;
291     uint8_t ipmbRqSlaveAddress;
292     uint8_t ipmbBusId;
293 
294     ipmbChannelType type;
295 
296     std::shared_ptr<IpmbCommandFilter> commandFilter;
297 
298     // array storing outstanding requests
299     std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount>
300         outstandingRequests;
301 
302     void requestTimerCallback(std::shared_ptr<IpmbRequest> request,
303                               std::shared_ptr<std::vector<uint8_t>> buffer);
304 
305     void responseMatch(std::unique_ptr<IpmbResponse> &response);
306 
307     void makeRequestInvalid(IpmbRequest &request);
308 
309     void makeRequestValid(std::shared_ptr<IpmbRequest> request);
310 };
311 
312 #endif
313