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 // TODO w/a to differentiate channel origin of incoming IPMI response: 149 // extracting channel number from 2 oldest bits of seq 150 constexpr ipmbChannelType getChannelFromSeq(const uint8_t &seq) 151 { 152 return static_cast<ipmbChannelType>((seq & 0xC0) >> 6); 153 } 154 155 /** 156 * @brief IpmbResponse declaration 157 */ 158 struct IpmbResponse 159 { 160 uint8_t address; 161 uint8_t netFn; 162 uint8_t rqLun; 163 uint8_t rsSA; 164 uint8_t seq; 165 uint8_t rsLun; 166 uint8_t cmd; 167 uint8_t completionCode; 168 std::vector<uint8_t> data; 169 170 IpmbResponse(); 171 172 IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, uint8_t rsSA, 173 uint8_t seq, uint8_t rsLun, uint8_t cmd, 174 uint8_t completionCode, std::vector<uint8_t> &inputData); 175 176 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength); 177 178 int ipmbToi2cConstruct(std::vector<uint8_t> &buffer); 179 }; 180 181 /** 182 * @brief IpmbRequest declaration 183 */ 184 struct IpmbRequest 185 { 186 uint8_t address; 187 uint8_t netFn; 188 uint8_t rsLun; 189 uint8_t rqSA; 190 uint8_t seq; 191 uint8_t rqLun; 192 uint8_t cmd; 193 std::vector<uint8_t> data; 194 195 size_t dataLength; 196 ipmbRequestState state; 197 std::optional<boost::asio::steady_timer> timer; 198 std::unique_ptr<IpmbResponse> matchedResponse; 199 200 // creates empty request with empty timer object 201 IpmbRequest(); 202 203 IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun, uint8_t rqSA, 204 uint8_t seq, uint8_t rqLun, uint8_t cmd, 205 std::vector<uint8_t> &inputData); 206 207 IpmbRequest(const IpmbRequest &) = delete; 208 IpmbRequest &operator=(IpmbRequest const &) = delete; 209 210 void incomingMessageHandler(); 211 212 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 213 returnMatchedResponse(); 214 215 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 216 returnStatusResponse(int status); 217 218 void i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer, size_t bufferLength); 219 220 int ipmbToi2cConstruct(std::vector<uint8_t> &buffer); 221 222 // TODO w/a to differentiate channel origin of incoming IPMI response: 223 // saving channel number at two oldest unused bits of seq 224 void addChannelToSeq(const ipmbChannelType &channelType); 225 }; 226 227 /** 228 * @brief Command filtering class declaration 229 * 230 * This feature provides simple mechanism for filtering out commands - which are 231 * not implemented in IPMI - on IPMB level, in order to reduce DBus traffic 232 */ 233 class IpmbCommandFilter 234 { 235 public: 236 // function checking if netFn & cmd combination exist in blocked command 237 // list 238 bool isBlocked(const uint8_t reqNetFn, const uint8_t cmd); 239 // function adding netfFn & cmd combination to the blocked command list 240 void addFilter(const uint8_t reqNetFn, const uint8_t cmd); 241 242 private: 243 boost::container::flat_set<std::pair<uint8_t, uint8_t>> unhandledCommands; 244 }; 245 246 /** 247 * @brief Command filtering defines 248 */ 249 250 constexpr uint8_t ipmbIpmiInvalidCommand = 0xC1; 251 252 constexpr uint8_t ipmbReqNetFnFromRespNetFn(uint8_t reqNetFn) 253 { 254 return reqNetFn & ~ipmbNetFnResponseMask; 255 } 256 257 /** 258 * @brief IpmbChannel class declaration 259 */ 260 class IpmbChannel 261 { 262 public: 263 IpmbChannel(boost::asio::io_service &io, uint8_t ipmbBmcSlaveAddress, 264 uint8_t ipmbRqSlaveAddress, ipmbChannelType type, 265 std::shared_ptr<IpmbCommandFilter> commandFilter); 266 267 IpmbChannel(const IpmbChannel &) = delete; 268 IpmbChannel &operator=(IpmbChannel const &) = delete; 269 270 int ipmbChannelInit(const char *ipmbI2cSlave, const char *ipmbI2cMaster); 271 272 bool seqNumGet(uint8_t &seq); 273 274 ipmbChannelType getChannelType(); 275 276 uint8_t getBmcSlaveAddress(); 277 278 uint8_t getRqSlaveAddress(); 279 280 void addFilter(const uint8_t respNetFn, const uint8_t cmd); 281 282 void processI2cEvent(); 283 284 void ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer, 285 size_t retriesAttempted); 286 287 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> 288 requestAdd(boost::asio::yield_context &yield, 289 std::shared_ptr<IpmbRequest> requestToSend); 290 291 private: 292 boost::asio::ip::tcp::socket i2cSlaveSocket; 293 boost::asio::posix::stream_descriptor i2cMasterSocket; 294 295 int ipmbi2cMasterFd; 296 int ipmbi2cSlaveFd; 297 298 uint8_t ipmbBmcSlaveAddress; 299 uint8_t ipmbRqSlaveAddress; 300 301 ipmbChannelType type; 302 303 std::shared_ptr<IpmbCommandFilter> commandFilter; 304 305 // array storing outstanding requests 306 std::array<std::shared_ptr<IpmbRequest>, ipmbMaxOutstandingRequestsCount> 307 outstandingRequests; 308 309 void requestTimerCallback(std::shared_ptr<IpmbRequest> request, 310 std::shared_ptr<std::vector<uint8_t>> buffer); 311 312 void responseMatch(std::unique_ptr<IpmbResponse> &response); 313 314 void makeRequestInvalid(IpmbRequest &request); 315 316 void makeRequestValid(std::shared_ptr<IpmbRequest> request); 317 }; 318 319 #endif 320