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