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