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 "ipmbbridged.hpp"
17a642a948SDawid Frycki
18a642a948SDawid Frycki #include "ipmbdefines.hpp"
19a642a948SDawid Frycki #include "ipmbutils.hpp"
20a642a948SDawid Frycki
218edcf1a0SQiang XU #include <boost/algorithm/string/replace.hpp>
221486b8acSEd Tanous #include <boost/asio/io_context.hpp>
2309027c0eSEd Tanous #include <boost/asio/write.hpp>
24fe0d38a0SPatrick Williams #include <nlohmann/json.hpp>
25fe0d38a0SPatrick Williams #include <phosphor-logging/log.hpp>
26fe0d38a0SPatrick Williams
278edcf1a0SQiang XU #include <filesystem>
28314862d9SAmithash Prasad #include <fstream>
297867cd70SJason M. Bills #include <list>
30a642a948SDawid Frycki #include <tuple>
31314862d9SAmithash Prasad #include <unordered_map>
32a642a948SDawid Frycki
33a642a948SDawid Frycki /**
34a642a948SDawid Frycki * @brief Dbus
35a642a948SDawid Frycki */
36a642a948SDawid Frycki static constexpr const char* ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
37a642a948SDawid Frycki static constexpr const char* ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
38a642a948SDawid Frycki static constexpr const char* ipmbDbusIntf = "org.openbmc.Ipmb";
39a642a948SDawid Frycki
401486b8acSEd Tanous boost::asio::io_context io;
41a642a948SDawid Frycki auto conn = std::make_shared<sdbusplus::asio::connection>(io);
42a642a948SDawid Frycki
43a642a948SDawid Frycki static std::list<IpmbChannel> ipmbChannels;
44314862d9SAmithash Prasad static const std::unordered_map<std::string, ipmbChannelType>
45314862d9SAmithash Prasad ipmbChannelTypeMap = {{"me", ipmbChannelType::me},
46314862d9SAmithash Prasad {"ipmb", ipmbChannelType::ipmb}};
47a642a948SDawid Frycki
48a642a948SDawid Frycki /**
49a642a948SDawid Frycki * @brief Ipmb request class methods
50a642a948SDawid Frycki */
IpmbRequest()51a642a948SDawid Frycki IpmbRequest::IpmbRequest()
52a642a948SDawid Frycki {
53a642a948SDawid Frycki data.reserve(ipmbMaxDataSize);
54a642a948SDawid Frycki }
55a642a948SDawid Frycki
IpmbRequest(uint8_t address,uint8_t netFn,uint8_t rsLun,uint8_t rqSA,uint8_t seq,uint8_t rqLun,uint8_t cmd,const std::vector<uint8_t> & inputData)56a642a948SDawid Frycki IpmbRequest::IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun,
57a642a948SDawid Frycki uint8_t rqSA, uint8_t seq, uint8_t rqLun, uint8_t cmd,
588188d765SDawid Frycki const std::vector<uint8_t>& inputData) :
59*9898d612SPatrick Williams address(address), netFn(netFn), rsLun(rsLun), rqSA(rqSA), seq(seq),
60*9898d612SPatrick Williams rqLun(rqLun), cmd(cmd), timer(io)
61a642a948SDawid Frycki {
62a642a948SDawid Frycki data.reserve(ipmbMaxDataSize);
63a642a948SDawid Frycki state = ipmbRequestState::invalid;
64a642a948SDawid Frycki
65a642a948SDawid Frycki if (inputData.size() > 0)
66a642a948SDawid Frycki {
67a642a948SDawid Frycki data = std::move(inputData);
68a642a948SDawid Frycki }
69a642a948SDawid Frycki }
70a642a948SDawid Frycki
i2cToIpmbConstruct(IPMB_HEADER * ipmbBuffer,size_t bufferLength)71a642a948SDawid Frycki void IpmbRequest::i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer,
72a642a948SDawid Frycki size_t bufferLength)
73a642a948SDawid Frycki {
74a642a948SDawid Frycki // constructing ipmb request from i2c buffer
75a642a948SDawid Frycki netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
76a642a948SDawid Frycki rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
77a642a948SDawid Frycki rqSA = ipmbBuffer->Header.Req.rqSA;
78a642a948SDawid Frycki seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
79a642a948SDawid Frycki rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
80a642a948SDawid Frycki cmd = ipmbBuffer->Header.Req.cmd;
81a642a948SDawid Frycki
82*9898d612SPatrick Williams size_t dataLength =
83*9898d612SPatrick Williams bufferLength - (ipmbConnectionHeaderLength +
84a642a948SDawid Frycki ipmbRequestDataHeaderLength + ipmbChecksumSize);
85a642a948SDawid Frycki
86a642a948SDawid Frycki if (dataLength > 0)
87a642a948SDawid Frycki {
88a642a948SDawid Frycki data.insert(data.end(), ipmbBuffer->Header.Req.data,
89a642a948SDawid Frycki &ipmbBuffer->Header.Req.data[dataLength]);
90a642a948SDawid Frycki }
91a642a948SDawid Frycki }
92a642a948SDawid Frycki
ipmbToi2cConstruct(std::vector<uint8_t> & buffer)93a642a948SDawid Frycki int IpmbRequest::ipmbToi2cConstruct(std::vector<uint8_t>& buffer)
94a642a948SDawid Frycki {
9537a7eaceSVijay Khemka /* Add one byte for length byte as per required by driver */
9637a7eaceSVijay Khemka size_t bufferLength = 1 + data.size() + ipmbRequestDataHeaderLength +
97a642a948SDawid Frycki ipmbConnectionHeaderLength + ipmbChecksumSize;
98a642a948SDawid Frycki
99a642a948SDawid Frycki if (bufferLength > ipmbMaxFrameLength)
100a642a948SDawid Frycki {
101a642a948SDawid Frycki return -1;
102a642a948SDawid Frycki }
103a642a948SDawid Frycki
104a642a948SDawid Frycki buffer.resize(bufferLength);
105a642a948SDawid Frycki static_assert(ipmbMaxFrameLength >= sizeof(IPMB_HEADER));
10637a7eaceSVijay Khemka IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer.data());
10737a7eaceSVijay Khemka ipmbPkt->len = bufferLength - 1;
10837a7eaceSVijay Khemka IPMB_HEADER* ipmbBuffer = &(ipmbPkt->hdr);
109a642a948SDawid Frycki
110a642a948SDawid Frycki // constructing buffer from ipmb request
111a642a948SDawid Frycki ipmbBuffer->Header.Req.address = address;
112a642a948SDawid Frycki ipmbBuffer->Header.Req.rsNetFnLUN = ipmbNetFnLunSet(netFn, rsLun);
113a642a948SDawid Frycki ipmbBuffer->Header.Req.rqSA = rqSA;
114a642a948SDawid Frycki ipmbBuffer->Header.Req.rqSeqLUN = ipmbSeqLunSet(seq, rqLun);
115a642a948SDawid Frycki ipmbBuffer->Header.Req.cmd = cmd;
116a642a948SDawid Frycki
117bbfd00abSQiang XU ipmbBuffer->Header.Req.checksum1 = ipmbChecksumCompute(
11837a7eaceSVijay Khemka (uint8_t*)ipmbBuffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
119a642a948SDawid Frycki
120a642a948SDawid Frycki if (data.size() > 0)
121a642a948SDawid Frycki {
122a642a948SDawid Frycki std::copy(data.begin(), data.end(), ipmbBuffer->Header.Req.data);
123a642a948SDawid Frycki }
124a642a948SDawid Frycki
125a642a948SDawid Frycki buffer[bufferLength - ipmbChecksumSize] =
12637a7eaceSVijay Khemka ipmbChecksumCompute((uint8_t*)ipmbBuffer + ipmbChecksum2StartOffset,
127a642a948SDawid Frycki (ipmbRequestDataHeaderLength + data.size()));
128a642a948SDawid Frycki
129a642a948SDawid Frycki return 0;
130a642a948SDawid Frycki }
131a642a948SDawid Frycki
132a642a948SDawid Frycki std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
returnMatchedResponse()133a642a948SDawid Frycki IpmbRequest::returnMatchedResponse()
134a642a948SDawid Frycki {
135a642a948SDawid Frycki return std::make_tuple(
136a642a948SDawid Frycki static_cast<int>(ipmbResponseStatus::success), matchedResponse->netFn,
137a642a948SDawid Frycki matchedResponse->rsLun, matchedResponse->cmd,
138a642a948SDawid Frycki matchedResponse->completionCode, matchedResponse->data);
139a642a948SDawid Frycki }
140a642a948SDawid Frycki
141a642a948SDawid Frycki static std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
returnStatus(ipmbResponseStatus status)142a642a948SDawid Frycki returnStatus(ipmbResponseStatus status)
143a642a948SDawid Frycki {
144a642a948SDawid Frycki // we only want to send status here, other fields are not relevant
145a642a948SDawid Frycki return std::make_tuple(static_cast<int>(status), 0, 0, 0, 0,
146a642a948SDawid Frycki std::vector<uint8_t>(0));
147a642a948SDawid Frycki }
148a642a948SDawid Frycki
149a642a948SDawid Frycki /**
150a642a948SDawid Frycki * @brief Ipmb response class methods
151a642a948SDawid Frycki */
IpmbResponse()152a642a948SDawid Frycki IpmbResponse::IpmbResponse()
153a642a948SDawid Frycki {
154a642a948SDawid Frycki data.reserve(ipmbMaxDataSize);
155a642a948SDawid Frycki }
156a642a948SDawid Frycki
IpmbResponse(uint8_t address,uint8_t netFn,uint8_t rqLun,uint8_t rsSA,uint8_t seq,uint8_t rsLun,uint8_t cmd,uint8_t completionCode,const std::vector<uint8_t> & inputData)157a642a948SDawid Frycki IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
158a642a948SDawid Frycki uint8_t rsSA, uint8_t seq, uint8_t rsLun,
159a642a948SDawid Frycki uint8_t cmd, uint8_t completionCode,
1608188d765SDawid Frycki const std::vector<uint8_t>& inputData) :
161*9898d612SPatrick Williams address(address), netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq),
162*9898d612SPatrick Williams rsLun(rsLun), cmd(cmd), completionCode(completionCode)
163a642a948SDawid Frycki {
164a642a948SDawid Frycki data.reserve(ipmbMaxDataSize);
165a642a948SDawid Frycki
166a642a948SDawid Frycki if (inputData.size() > 0)
167a642a948SDawid Frycki {
168a642a948SDawid Frycki data = std::move(inputData);
169a642a948SDawid Frycki }
170a642a948SDawid Frycki }
171a642a948SDawid Frycki
i2cToIpmbConstruct(IPMB_HEADER * ipmbBuffer,size_t bufferLength)172a642a948SDawid Frycki void IpmbResponse::i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer,
173a642a948SDawid Frycki size_t bufferLength)
174a642a948SDawid Frycki {
175a642a948SDawid Frycki netFn = ipmbNetFnGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
176a642a948SDawid Frycki rqLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
177a642a948SDawid Frycki rsSA = ipmbBuffer->Header.Resp.rsSA;
178a642a948SDawid Frycki seq = ipmbSeqGet(ipmbBuffer->Header.Resp.rsSeqLUN);
179a642a948SDawid Frycki rsLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Resp.rsSeqLUN);
180a642a948SDawid Frycki cmd = ipmbBuffer->Header.Resp.cmd;
181a642a948SDawid Frycki completionCode = ipmbBuffer->Header.Resp.completionCode;
182a642a948SDawid Frycki
183*9898d612SPatrick Williams size_t dataLength =
184*9898d612SPatrick Williams bufferLength - (ipmbConnectionHeaderLength +
185a642a948SDawid Frycki ipmbResponseDataHeaderLength + ipmbChecksumSize);
186a642a948SDawid Frycki
187a642a948SDawid Frycki if (dataLength > 0)
188a642a948SDawid Frycki {
189a642a948SDawid Frycki data.insert(data.end(), ipmbBuffer->Header.Resp.data,
190a642a948SDawid Frycki &ipmbBuffer->Header.Resp.data[dataLength]);
191a642a948SDawid Frycki }
192a642a948SDawid Frycki }
193a642a948SDawid Frycki
ipmbToi2cConstruct()1948188d765SDawid Frycki std::shared_ptr<std::vector<uint8_t>> IpmbResponse::ipmbToi2cConstruct()
195a642a948SDawid Frycki {
19637a7eaceSVijay Khemka /* Add one byte for length byte as per required by driver */
19737a7eaceSVijay Khemka size_t bufferLength = 1 + data.size() + ipmbResponseDataHeaderLength +
198a642a948SDawid Frycki ipmbConnectionHeaderLength + ipmbChecksumSize;
199a642a948SDawid Frycki
200a642a948SDawid Frycki if (bufferLength > ipmbMaxFrameLength)
201a642a948SDawid Frycki {
2028188d765SDawid Frycki return nullptr;
203a642a948SDawid Frycki }
204a642a948SDawid Frycki
2058188d765SDawid Frycki std::shared_ptr<std::vector<uint8_t>> buffer =
2068188d765SDawid Frycki std::make_shared<std::vector<uint8_t>>(bufferLength);
2078188d765SDawid Frycki
20837a7eaceSVijay Khemka IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer->data());
20937a7eaceSVijay Khemka ipmbPkt->len = bufferLength - 1;
21037a7eaceSVijay Khemka IPMB_HEADER* ipmbBuffer = &(ipmbPkt->hdr);
211a642a948SDawid Frycki
212a642a948SDawid Frycki ipmbBuffer->Header.Resp.address = address;
213a642a948SDawid Frycki ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
214a642a948SDawid Frycki ipmbBuffer->Header.Resp.rsSA = rsSA;
215a642a948SDawid Frycki ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
216a642a948SDawid Frycki ipmbBuffer->Header.Resp.cmd = cmd;
217a642a948SDawid Frycki ipmbBuffer->Header.Resp.completionCode = completionCode;
218a642a948SDawid Frycki
219a642a948SDawid Frycki ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
22037a7eaceSVijay Khemka (uint8_t*)ipmbBuffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
221a642a948SDawid Frycki
222a642a948SDawid Frycki if (data.size() > 0)
223a642a948SDawid Frycki {
224a642a948SDawid Frycki std::copy(data.begin(), data.end(), ipmbBuffer->Header.Resp.data);
225a642a948SDawid Frycki }
226a642a948SDawid Frycki
2278188d765SDawid Frycki (*buffer)[bufferLength - ipmbChecksumSize] =
22837a7eaceSVijay Khemka ipmbChecksumCompute((uint8_t*)ipmbBuffer + ipmbChecksum2StartOffset,
229a642a948SDawid Frycki (ipmbResponseDataHeaderLength + data.size()));
230a642a948SDawid Frycki
2318188d765SDawid Frycki return buffer;
232a642a948SDawid Frycki }
233a642a948SDawid Frycki
isBlocked(const uint8_t reqNetFn,const uint8_t cmd)234a642a948SDawid Frycki bool IpmbCommandFilter::isBlocked(const uint8_t reqNetFn, const uint8_t cmd)
235a642a948SDawid Frycki {
236a642a948SDawid Frycki auto blockedCmd = unhandledCommands.find({reqNetFn, cmd});
237a642a948SDawid Frycki
238a642a948SDawid Frycki if (blockedCmd != unhandledCommands.end())
239a642a948SDawid Frycki {
240a642a948SDawid Frycki return true;
241a642a948SDawid Frycki }
242a642a948SDawid Frycki
243a642a948SDawid Frycki return false;
244a642a948SDawid Frycki }
245a642a948SDawid Frycki
addFilter(const uint8_t reqNetFn,const uint8_t cmd)246a642a948SDawid Frycki void IpmbCommandFilter::addFilter(const uint8_t reqNetFn, const uint8_t cmd)
247a642a948SDawid Frycki {
248a642a948SDawid Frycki if (unhandledCommands.insert({reqNetFn, cmd}).second)
249a642a948SDawid Frycki {
250a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::INFO>(
251a642a948SDawid Frycki "addFilter: added command to filter",
252a642a948SDawid Frycki phosphor::logging::entry("netFn = %d", reqNetFn),
253a642a948SDawid Frycki phosphor::logging::entry("cmd = %d", cmd));
254a642a948SDawid Frycki }
255a642a948SDawid Frycki }
256a642a948SDawid Frycki
257a642a948SDawid Frycki /**
258a642a948SDawid Frycki * @brief Ipmb channel
259a642a948SDawid Frycki */
ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,size_t retriesAttempted=0)260bbfd00abSQiang XU void IpmbChannel::ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
261a642a948SDawid Frycki size_t retriesAttempted = 0)
262a642a948SDawid Frycki {
26337a7eaceSVijay Khemka IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer->data());
26437a7eaceSVijay Khemka uint8_t targetAddr = ipmbIsResponse(&(ipmbPkt->hdr))
26537a7eaceSVijay Khemka ? ipmbPkt->hdr.Header.Resp.address
26637a7eaceSVijay Khemka : ipmbPkt->hdr.Header.Req.address;
267*9898d612SPatrick Williams boost::asio::async_write(
268*9898d612SPatrick Williams i2cTargetDescriptor, boost::asio::buffer(*buffer),
269*9898d612SPatrick Williams [this, buffer, retriesAttempted, targetAddr](
270*9898d612SPatrick Williams const boost::system::error_code& ec, size_t /* bytesSent */) {
271a642a948SDawid Frycki if (ec)
272a642a948SDawid Frycki {
273a642a948SDawid Frycki size_t currentRetryCnt = retriesAttempted;
27437a7eaceSVijay Khemka
275a642a948SDawid Frycki if (currentRetryCnt > ipmbI2cNumberOfRetries)
276a642a948SDawid Frycki {
277bbfd00abSQiang XU std::string msgToLog =
27837a7eaceSVijay Khemka "ipmbSendI2cFrame: send to I2C failed after retries."
279bbfd00abSQiang XU " busId=" +
280bbfd00abSQiang XU std::to_string(ipmbBusId) +
281bbfd00abSQiang XU ", targetAddr=" + std::to_string(targetAddr) +
282bbfd00abSQiang XU ", error=" + ec.message();
283a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
284bbfd00abSQiang XU msgToLog.c_str());
285a642a948SDawid Frycki return;
286a642a948SDawid Frycki }
287a642a948SDawid Frycki currentRetryCnt++;
288bbfd00abSQiang XU ipmbSendI2cFrame(buffer, currentRetryCnt);
289a642a948SDawid Frycki }
290a642a948SDawid Frycki });
291a642a948SDawid Frycki }
292a642a948SDawid Frycki
293a642a948SDawid Frycki /**
294a642a948SDawid Frycki * @brief Ipmb Outstanding Requests
295a642a948SDawid Frycki */
makeRequestInvalid(IpmbRequest & request)296a642a948SDawid Frycki void IpmbChannel::makeRequestInvalid(IpmbRequest& request)
297a642a948SDawid Frycki {
298a642a948SDawid Frycki // change request state to invalid and remove it from outstanding requests
299a642a948SDawid Frycki // list
300a642a948SDawid Frycki request.state = ipmbRequestState::invalid;
301a642a948SDawid Frycki outstandingRequests[request.seq] = nullptr;
302a642a948SDawid Frycki }
303a642a948SDawid Frycki
makeRequestValid(std::shared_ptr<IpmbRequest> request)304a642a948SDawid Frycki void IpmbChannel::makeRequestValid(std::shared_ptr<IpmbRequest> request)
305a642a948SDawid Frycki {
306a642a948SDawid Frycki // change request state to valid and add it to outstanding requests list
307a642a948SDawid Frycki request->state = ipmbRequestState::valid;
308a642a948SDawid Frycki outstandingRequests[request->seq] = request;
309a642a948SDawid Frycki }
310a642a948SDawid Frycki
seqNumGet(uint8_t & seq)311a642a948SDawid Frycki bool IpmbChannel::seqNumGet(uint8_t& seq)
312a642a948SDawid Frycki {
313a642a948SDawid Frycki static uint8_t seqNum = 0;
314a642a948SDawid Frycki
315a642a948SDawid Frycki for (int i = 0; i < ipmbMaxOutstandingRequestsCount; i++)
316a642a948SDawid Frycki {
317e523af33SPatrick Williams seqNum = (seqNum + 1) % ipmbMaxOutstandingRequestsCount;
318a642a948SDawid Frycki
319a642a948SDawid Frycki if (outstandingRequests[seqNum] == nullptr)
320a642a948SDawid Frycki {
321a642a948SDawid Frycki seq = seqNum;
322a642a948SDawid Frycki return true;
323a642a948SDawid Frycki }
324a642a948SDawid Frycki }
325a642a948SDawid Frycki
326a642a948SDawid Frycki return false;
327a642a948SDawid Frycki }
328a642a948SDawid Frycki
responseMatch(std::unique_ptr<IpmbResponse> & response)329a642a948SDawid Frycki void IpmbChannel::responseMatch(std::unique_ptr<IpmbResponse>& response)
330a642a948SDawid Frycki {
331a642a948SDawid Frycki std::shared_ptr<IpmbRequest> request = outstandingRequests[response->seq];
332a642a948SDawid Frycki
333a642a948SDawid Frycki if (request != nullptr)
334a642a948SDawid Frycki {
335a642a948SDawid Frycki if (((ipmbRespNetFn(request->netFn)) == (response->netFn)) &&
336a642a948SDawid Frycki ((request->rqLun) == (response->rqLun)) &&
337a642a948SDawid Frycki ((request->rsLun) == (response->rsLun)) &&
338a642a948SDawid Frycki ((request->cmd) == (response->cmd)))
339a642a948SDawid Frycki {
340a642a948SDawid Frycki // match, response is corresponding to previously sent request
341a642a948SDawid Frycki request->state = ipmbRequestState::matched;
342a642a948SDawid Frycki request->timer->cancel();
343a642a948SDawid Frycki request->matchedResponse = std::move(response);
344a642a948SDawid Frycki }
345a642a948SDawid Frycki }
346a642a948SDawid Frycki }
347a642a948SDawid Frycki
processI2cEvent()348a642a948SDawid Frycki void IpmbChannel::processI2cEvent()
349a642a948SDawid Frycki {
350a642a948SDawid Frycki std::array<uint8_t, ipmbMaxFrameLength> buffer{};
35137a7eaceSVijay Khemka IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer.data());
35237a7eaceSVijay Khemka IPMB_HEADER* ipmbFrame = &(ipmbPkt->hdr);
353a642a948SDawid Frycki
3540736e213SMatt Simmering lseek(ipmbi2cTargetFd, 0, SEEK_SET);
3550736e213SMatt Simmering ssize_t r = read(ipmbi2cTargetFd, buffer.data(), ipmbMaxFrameLength);
3561f5b24baSPatrick Williams
3571f5b24baSPatrick Williams // Handle error cases.
3581f5b24baSPatrick Williams if (r < 0)
3591f5b24baSPatrick Williams {
3601f5b24baSPatrick Williams goto end;
3611f5b24baSPatrick Williams }
36237a7eaceSVijay Khemka
363524f753fSManojkiran Eda /* Subtract first byte len size from total frame length */
36437a7eaceSVijay Khemka r--;
36537a7eaceSVijay Khemka
366a642a948SDawid Frycki if ((r < ipmbMinFrameLength) || (r > ipmbMaxFrameLength))
367a642a948SDawid Frycki {
368a642a948SDawid Frycki goto end;
369a642a948SDawid Frycki }
370a642a948SDawid Frycki
371524f753fSManojkiran Eda // validate the frame
372a642a948SDawid Frycki if (!isFrameValid(ipmbFrame, r))
373a642a948SDawid Frycki {
374a642a948SDawid Frycki goto end;
375a642a948SDawid Frycki }
376a642a948SDawid Frycki
37715185ff6SChen Yugang // if it is message received from ipmb channel, send out dbus signal
37815185ff6SChen Yugang if (getChannelType() == ipmbChannelType::ipmb)
379bbfd00abSQiang XU {
380bbfd00abSQiang XU auto ipmbMessageReceived = IpmbRequest();
381bbfd00abSQiang XU ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
382*9898d612SPatrick Williams sdbusplus::message_t msg =
383*9898d612SPatrick Williams conn->new_signal(ipmbObj, ipmbDbusIntf, "receiveBroadcast");
384bbfd00abSQiang XU msg.append(ipmbMessageReceived.netFn, ipmbMessageReceived.cmd,
385bbfd00abSQiang XU ipmbMessageReceived.data);
386bbfd00abSQiang XU msg.signal_send();
387bbfd00abSQiang XU }
388bbfd00abSQiang XU
389a642a948SDawid Frycki // copy frame to ipmib message buffer
3903e07b9eaSChen Yugang if (ipmbIsResponse(ipmbFrame))
391a642a948SDawid Frycki {
392a642a948SDawid Frycki std::unique_ptr<IpmbResponse> ipmbMessageReceived =
393a642a948SDawid Frycki std::make_unique<IpmbResponse>();
394a642a948SDawid Frycki
395a642a948SDawid Frycki ipmbMessageReceived->i2cToIpmbConstruct(ipmbFrame, r);
396a642a948SDawid Frycki
397a642a948SDawid Frycki // try to match response with outstanding request
398a642a948SDawid Frycki responseMatch(ipmbMessageReceived);
399a642a948SDawid Frycki }
400a642a948SDawid Frycki else
401a642a948SDawid Frycki {
402a642a948SDawid Frycki // if command is blocked - respond with 'invalid command'
403a642a948SDawid Frycki // completion code
404a642a948SDawid Frycki if (commandFilter)
405a642a948SDawid Frycki {
406a642a948SDawid Frycki uint8_t netFn = ipmbNetFnGet(ipmbFrame->Header.Req.rsNetFnLUN);
407a642a948SDawid Frycki uint8_t cmd = ipmbFrame->Header.Req.cmd;
408bbfd00abSQiang XU uint8_t rqSA = ipmbFrame->Header.Req.rqSA;
409a642a948SDawid Frycki
410a642a948SDawid Frycki if (commandFilter->isBlocked(netFn, cmd))
411a642a948SDawid Frycki {
412a642a948SDawid Frycki uint8_t seq = ipmbSeqGet(ipmbFrame->Header.Req.rqSeqLUN);
413a642a948SDawid Frycki uint8_t lun =
414a642a948SDawid Frycki ipmbLunFromSeqLunGet(ipmbFrame->Header.Req.rqSeqLUN);
415a642a948SDawid Frycki
416a642a948SDawid Frycki // prepare generic response
417bbfd00abSQiang XU auto ipmbResponse = IpmbResponse(
4180736e213SMatt Simmering rqSA, ipmbRespNetFn(netFn), lun, ipmbBmcTargetAddress, seq,
419bbfd00abSQiang XU ipmbRsLun, cmd, ipmbIpmiInvalidCmd, {});
420a642a948SDawid Frycki
4218188d765SDawid Frycki auto buffer = ipmbResponse.ipmbToi2cConstruct();
4228188d765SDawid Frycki if (buffer)
423a642a948SDawid Frycki {
424bbfd00abSQiang XU ipmbSendI2cFrame(buffer);
425a642a948SDawid Frycki }
426a642a948SDawid Frycki
427a642a948SDawid Frycki goto end;
428a642a948SDawid Frycki }
429a642a948SDawid Frycki }
430a642a948SDawid Frycki
431a642a948SDawid Frycki auto ipmbMessageReceived = IpmbRequest();
432a642a948SDawid Frycki ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
433a642a948SDawid Frycki
4348fe0abe6SKumar Thangavel int devId = getDevIndex();
4358fe0abe6SKumar Thangavel
4368188d765SDawid Frycki std::map<std::string, std::variant<int>> options{
4378fe0abe6SKumar Thangavel {"rqSA", ipmbAddressTo7BitSet(ipmbMessageReceived.rqSA)},
4388fe0abe6SKumar Thangavel {"hostId", devId}};
4398fe0abe6SKumar Thangavel
4408188d765SDawid Frycki using IpmiDbusRspType = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t,
4418188d765SDawid Frycki std::vector<uint8_t>>;
4428188d765SDawid Frycki conn->async_method_call(
4438188d765SDawid Frycki [this, rqLun{ipmbMessageReceived.rqLun},
444bbfd00abSQiang XU seq{ipmbMessageReceived.seq}, address{ipmbMessageReceived.rqSA}](
445bbfd00abSQiang XU const boost::system::error_code& ec,
4468188d765SDawid Frycki const IpmiDbusRspType& response) {
4478188d765SDawid Frycki const auto& [netfn, lun, cmd, cc, payload] = response;
4488188d765SDawid Frycki if (ec)
4498188d765SDawid Frycki {
4508188d765SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
4518188d765SDawid Frycki "processI2cEvent: error getting response from IPMI");
4528188d765SDawid Frycki return;
4538188d765SDawid Frycki }
454a642a948SDawid Frycki
4550736e213SMatt Simmering uint8_t bmcTargetAddress = getBmcTargetAddress();
4568188d765SDawid Frycki
4578188d765SDawid Frycki if (payload.size() > ipmbMaxDataSize)
4588188d765SDawid Frycki {
4598188d765SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
4608188d765SDawid Frycki "processI2cEvent: response exceeding maximum size");
4618188d765SDawid Frycki
4628188d765SDawid Frycki // prepare generic response
4638188d765SDawid Frycki auto ipmbResponse = IpmbResponse(
4640736e213SMatt Simmering address, netfn, rqLun, bmcTargetAddress, seq, ipmbRsLun,
4650736e213SMatt Simmering cmd, ipmbIpmiCmdRespNotProvided, {});
4668188d765SDawid Frycki
4678188d765SDawid Frycki auto buffer = ipmbResponse.ipmbToi2cConstruct();
4688188d765SDawid Frycki if (buffer)
4698188d765SDawid Frycki {
470bbfd00abSQiang XU ipmbSendI2cFrame(buffer);
4718188d765SDawid Frycki }
4728188d765SDawid Frycki
4738188d765SDawid Frycki return;
4748188d765SDawid Frycki }
4758188d765SDawid Frycki
4768188d765SDawid Frycki if (!(netfn & ipmbNetFnResponseMask))
4778188d765SDawid Frycki {
4788188d765SDawid Frycki // we are not expecting request here
4798188d765SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
4808188d765SDawid Frycki "processI2cEvent: got a request instead of response");
4818188d765SDawid Frycki return;
4828188d765SDawid Frycki }
4838188d765SDawid Frycki
4848188d765SDawid Frycki // if command is not supported, add it to filter
4858188d765SDawid Frycki if (cc == ipmbIpmiInvalidCmd)
4868188d765SDawid Frycki {
4878188d765SDawid Frycki addFilter(ipmbReqNetFnFromRespNetFn(netfn), cmd);
4888188d765SDawid Frycki }
4898188d765SDawid Frycki
4908188d765SDawid Frycki // payload is empty after constructor invocation
491*9898d612SPatrick Williams auto ipmbResponse =
492*9898d612SPatrick Williams IpmbResponse(address, netfn, rqLun, bmcTargetAddress, seq,
493*9898d612SPatrick Williams lun, cmd, cc, payload);
4948188d765SDawid Frycki
4958188d765SDawid Frycki auto buffer = ipmbResponse.ipmbToi2cConstruct();
4968188d765SDawid Frycki if (!buffer)
4978188d765SDawid Frycki {
4988188d765SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
4998188d765SDawid Frycki "processI2cEvent: error constructing a request");
5008188d765SDawid Frycki return;
5018188d765SDawid Frycki }
5028188d765SDawid Frycki
503bbfd00abSQiang XU ipmbSendI2cFrame(buffer);
5048188d765SDawid Frycki },
5058188d765SDawid Frycki "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
5068188d765SDawid Frycki "xyz.openbmc_project.Ipmi.Server", "execute",
5078188d765SDawid Frycki ipmbMessageReceived.netFn, ipmbMessageReceived.rsLun,
5088188d765SDawid Frycki ipmbMessageReceived.cmd, ipmbMessageReceived.data, options);
509a642a948SDawid Frycki }
510a642a948SDawid Frycki
511a642a948SDawid Frycki end:
5120736e213SMatt Simmering i2cTargetDescriptor.async_wait(
51337a7eaceSVijay Khemka boost::asio::posix::descriptor_base::wait_read,
514a642a948SDawid Frycki [this](const boost::system::error_code& ec) {
515a642a948SDawid Frycki if (ec)
516a642a948SDawid Frycki {
517a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
518a642a948SDawid Frycki "Error: processI2cEvent()");
519a642a948SDawid Frycki return;
520a642a948SDawid Frycki }
521a642a948SDawid Frycki
522a642a948SDawid Frycki processI2cEvent();
523a642a948SDawid Frycki });
524a642a948SDawid Frycki }
525a642a948SDawid Frycki
IpmbChannel(boost::asio::io_context & io,uint8_t ipmbBmcTargetAddress,uint8_t ipmbRqTargetAddress,uint8_t channelIdx,std::shared_ptr<IpmbCommandFilter> commandFilter)5261486b8acSEd Tanous IpmbChannel::IpmbChannel(boost::asio::io_context& io,
5270736e213SMatt Simmering uint8_t ipmbBmcTargetAddress,
5280736e213SMatt Simmering uint8_t ipmbRqTargetAddress, uint8_t channelIdx,
529a642a948SDawid Frycki std::shared_ptr<IpmbCommandFilter> commandFilter) :
530*9898d612SPatrick Williams i2cTargetDescriptor(io), ipmbBmcTargetAddress(ipmbBmcTargetAddress),
5310736e213SMatt Simmering ipmbRqTargetAddress(ipmbRqTargetAddress), channelIdx(channelIdx),
532a642a948SDawid Frycki commandFilter(commandFilter)
533fe0d38a0SPatrick Williams {}
534a642a948SDawid Frycki
ipmbChannelInit(const char * ipmbI2cTarget)5350736e213SMatt Simmering int IpmbChannel::ipmbChannelInit(const char* ipmbI2cTarget)
536a642a948SDawid Frycki {
5370736e213SMatt Simmering // extract bus id from target path and save
5380736e213SMatt Simmering std::string ipmbI2cTargetStr(ipmbI2cTarget);
5390736e213SMatt Simmering auto findHyphen = ipmbI2cTargetStr.find("-");
5400736e213SMatt Simmering std::string busStr = ipmbI2cTargetStr.substr(findHyphen + 1);
5418edcf1a0SQiang XU try
5428edcf1a0SQiang XU {
5438edcf1a0SQiang XU ipmbBusId = std::stoi(busStr);
5448edcf1a0SQiang XU }
545c0dd70d8SPatrick Williams catch (const std::invalid_argument&)
5468edcf1a0SQiang XU {
5478edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
5480736e213SMatt Simmering "ipmbChannelInit: invalid bus id in target-path config");
5498edcf1a0SQiang XU return -1;
5508edcf1a0SQiang XU }
5518edcf1a0SQiang XU
5520736e213SMatt Simmering // Check if sysfs has device. If not, enable I2C target driver by command
55337a7eaceSVijay Khemka // echo "ipmb-dev 0x1010" > /sys/bus/i2c/devices/i2c-0/new_device
5540736e213SMatt Simmering bool hasSysfs = std::filesystem::exists(ipmbI2cTarget);
5558edcf1a0SQiang XU if (!hasSysfs)
5568edcf1a0SQiang XU {
557*9898d612SPatrick Williams std::string deviceFileName =
558*9898d612SPatrick Williams "/sys/bus/i2c/devices/i2c-" + busStr + "/new_device";
55937a7eaceSVijay Khemka std::string para = "ipmb-dev 0x1010"; // init with BMC addr 0x20
5608edcf1a0SQiang XU std::fstream deviceFile;
5618edcf1a0SQiang XU deviceFile.open(deviceFileName, std::ios::out);
5628edcf1a0SQiang XU if (!deviceFile.good())
5638edcf1a0SQiang XU {
5648edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
5658edcf1a0SQiang XU "ipmbChannelInit: error opening deviceFile");
5668edcf1a0SQiang XU return -1;
5678edcf1a0SQiang XU }
5688edcf1a0SQiang XU deviceFile << para;
5698edcf1a0SQiang XU deviceFile.close();
5708edcf1a0SQiang XU }
5718edcf1a0SQiang XU
5720736e213SMatt Simmering // open fd to i2c target device for read write
5730736e213SMatt Simmering ipmbi2cTargetFd = open(ipmbI2cTarget, O_RDWR | O_NONBLOCK | O_CLOEXEC);
5740736e213SMatt Simmering if (ipmbi2cTargetFd < 0)
575a642a948SDawid Frycki {
576a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
5770736e213SMatt Simmering "ipmbChannelInit: error opening ipmbI2cTarget");
578a642a948SDawid Frycki return -1;
579a642a948SDawid Frycki }
580a642a948SDawid Frycki
5810736e213SMatt Simmering i2cTargetDescriptor.assign(ipmbi2cTargetFd);
582a642a948SDawid Frycki
5830736e213SMatt Simmering i2cTargetDescriptor.async_wait(
58437a7eaceSVijay Khemka boost::asio::posix::descriptor_base::wait_read,
585a642a948SDawid Frycki [this](const boost::system::error_code& ec) {
586a642a948SDawid Frycki if (ec)
587a642a948SDawid Frycki {
588a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
589a642a948SDawid Frycki "Error: processI2cEvent()");
590a642a948SDawid Frycki return;
591a642a948SDawid Frycki }
592a642a948SDawid Frycki
593a642a948SDawid Frycki processI2cEvent();
594a642a948SDawid Frycki });
595a642a948SDawid Frycki
596a642a948SDawid Frycki return 0;
597a642a948SDawid Frycki }
598a642a948SDawid Frycki
ipmbChannelUpdateTargetAddress(const uint8_t newBmcTargetAddr)5990736e213SMatt Simmering int IpmbChannel::ipmbChannelUpdateTargetAddress(const uint8_t newBmcTargetAddr)
6008edcf1a0SQiang XU {
6010736e213SMatt Simmering if (ipmbi2cTargetFd > 0)
6028edcf1a0SQiang XU {
6030736e213SMatt Simmering i2cTargetDescriptor.close();
6040736e213SMatt Simmering close(ipmbi2cTargetFd);
6050736e213SMatt Simmering ipmbi2cTargetFd = 0;
6068edcf1a0SQiang XU }
6078edcf1a0SQiang XU
6080736e213SMatt Simmering // disable old I2C target driver by command:
6098edcf1a0SQiang XU // echo "0x1010" > /sys/bus/i2c/devices/i2c-0/delete_device
6108edcf1a0SQiang XU std::string deviceFileName;
6118edcf1a0SQiang XU std::string para;
6128edcf1a0SQiang XU std::fstream deviceFile;
6138edcf1a0SQiang XU deviceFileName = "/sys/bus/i2c/devices/i2c-" + std::to_string(ipmbBusId) +
6148edcf1a0SQiang XU "/delete_device";
6158edcf1a0SQiang XU para = "0x1010"; // align with removed ipmb0 definition in dts file
6168edcf1a0SQiang XU deviceFile.open(deviceFileName, std::ios::out);
6178edcf1a0SQiang XU if (!deviceFile.good())
6188edcf1a0SQiang XU {
6198edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
6200736e213SMatt Simmering "ipmbChannelUpdateTargetAddress: error opening deviceFile to delete "
6218edcf1a0SQiang XU "sysfs");
6228edcf1a0SQiang XU return -1;
6238edcf1a0SQiang XU }
6248edcf1a0SQiang XU deviceFile << para;
6258edcf1a0SQiang XU deviceFile.close();
6268edcf1a0SQiang XU
6270736e213SMatt Simmering // enable new I2C target driver by command:
62837a7eaceSVijay Khemka // echo "ipmb-dev 0x1012" > /sys/bus/i2c/devices/i2c-0/new_device
629*9898d612SPatrick Williams deviceFileName =
630*9898d612SPatrick Williams "/sys/bus/i2c/devices/i2c-" + std::to_string(ipmbBusId) + "/new_device";
6318edcf1a0SQiang XU std::ostringstream hex;
6320736e213SMatt Simmering uint16_t addr = 0x1000 + (newBmcTargetAddr >> 1);
6338edcf1a0SQiang XU hex << std::hex << static_cast<uint16_t>(addr);
6348edcf1a0SQiang XU const std::string& addressHexStr = hex.str();
63537a7eaceSVijay Khemka para = "ipmb-dev 0x" + addressHexStr;
6368edcf1a0SQiang XU deviceFile.open(deviceFileName, std::ios::out);
6378edcf1a0SQiang XU if (!deviceFile.good())
6388edcf1a0SQiang XU {
6398edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
6400736e213SMatt Simmering "ipmbChannelUpdateTargetAddress: error opening deviceFile to create "
6418edcf1a0SQiang XU "sysfs");
6428edcf1a0SQiang XU return -1;
6438edcf1a0SQiang XU }
6448edcf1a0SQiang XU deviceFile << para;
6458edcf1a0SQiang XU deviceFile.close();
6468edcf1a0SQiang XU
6470736e213SMatt Simmering // open fd to i2c target device
6480736e213SMatt Simmering std::string ipmbI2cTargetStr = "/dev/ipmb-" + std::to_string(ipmbBusId);
6490736e213SMatt Simmering ipmbi2cTargetFd = open(ipmbI2cTargetStr.c_str(), O_RDWR | O_NONBLOCK);
6500736e213SMatt Simmering if (ipmbi2cTargetFd < 0)
6518edcf1a0SQiang XU {
6528edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
6530736e213SMatt Simmering "ipmbChannelInit: error opening ipmbI2cTarget");
6548edcf1a0SQiang XU return -1;
6558edcf1a0SQiang XU }
6568edcf1a0SQiang XU
6570736e213SMatt Simmering // start to receive i2c data as target
6580736e213SMatt Simmering i2cTargetDescriptor.assign(ipmbi2cTargetFd);
6590736e213SMatt Simmering i2cTargetDescriptor.async_wait(
66037a7eaceSVijay Khemka boost::asio::posix::descriptor_base::wait_read,
6618edcf1a0SQiang XU [this](const boost::system::error_code& ec) {
6628edcf1a0SQiang XU if (ec)
6638edcf1a0SQiang XU {
6648edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
6658edcf1a0SQiang XU "Error: processI2cEvent()");
6668edcf1a0SQiang XU return;
6678edcf1a0SQiang XU }
6688edcf1a0SQiang XU
6698edcf1a0SQiang XU processI2cEvent();
6708edcf1a0SQiang XU });
6718edcf1a0SQiang XU
6720736e213SMatt Simmering ipmbBmcTargetAddress = newBmcTargetAddr;
673bbfd00abSQiang XU
6748edcf1a0SQiang XU return 0;
6758edcf1a0SQiang XU }
6768edcf1a0SQiang XU
getBusId()6778edcf1a0SQiang XU uint8_t IpmbChannel::getBusId()
6788edcf1a0SQiang XU {
6798edcf1a0SQiang XU return ipmbBusId;
6808edcf1a0SQiang XU }
6818edcf1a0SQiang XU
getBmcTargetAddress()6820736e213SMatt Simmering uint8_t IpmbChannel::getBmcTargetAddress()
683a642a948SDawid Frycki {
6840736e213SMatt Simmering return ipmbBmcTargetAddress;
685a642a948SDawid Frycki }
686a642a948SDawid Frycki
getRqTargetAddress()6870736e213SMatt Simmering uint8_t IpmbChannel::getRqTargetAddress()
688a642a948SDawid Frycki {
6890736e213SMatt Simmering return ipmbRqTargetAddress;
690a642a948SDawid Frycki }
691a642a948SDawid Frycki
getDevIndex()692950a2e81SKumar Thangavel uint8_t IpmbChannel::getDevIndex()
693950a2e81SKumar Thangavel {
694950a2e81SKumar Thangavel return channelIdx >> 2;
695950a2e81SKumar Thangavel }
696950a2e81SKumar Thangavel
getChannelIdx()697950a2e81SKumar Thangavel uint8_t IpmbChannel::getChannelIdx()
698950a2e81SKumar Thangavel {
699950a2e81SKumar Thangavel return channelIdx;
700950a2e81SKumar Thangavel }
701950a2e81SKumar Thangavel
getChannelType()702a642a948SDawid Frycki ipmbChannelType IpmbChannel::getChannelType()
703a642a948SDawid Frycki {
704950a2e81SKumar Thangavel return static_cast<ipmbChannelType>((channelIdx & 3));
705a642a948SDawid Frycki }
706a642a948SDawid Frycki
addFilter(const uint8_t respNetFn,const uint8_t cmd)707a642a948SDawid Frycki void IpmbChannel::addFilter(const uint8_t respNetFn, const uint8_t cmd)
708a642a948SDawid Frycki {
709a642a948SDawid Frycki if (commandFilter)
710a642a948SDawid Frycki {
711a642a948SDawid Frycki commandFilter->addFilter(respNetFn, cmd);
712a642a948SDawid Frycki }
713a642a948SDawid Frycki }
714a642a948SDawid Frycki
715a642a948SDawid Frycki std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
requestAdd(boost::asio::yield_context & yield,std::shared_ptr<IpmbRequest> request)716a642a948SDawid Frycki IpmbChannel::requestAdd(boost::asio::yield_context& yield,
717a642a948SDawid Frycki std::shared_ptr<IpmbRequest> request)
718a642a948SDawid Frycki {
719a642a948SDawid Frycki makeRequestValid(request);
720a642a948SDawid Frycki
7219ae88935SPatrick Williams std::vector<uint8_t> buffer{};
722a642a948SDawid Frycki if (request->ipmbToi2cConstruct(buffer) != 0)
723a642a948SDawid Frycki {
724a642a948SDawid Frycki return returnStatus(ipmbResponseStatus::error);
725a642a948SDawid Frycki }
726a642a948SDawid Frycki
727a642a948SDawid Frycki for (int i = 0; i < ipmbNumberOfTries; i++)
728a642a948SDawid Frycki {
729a642a948SDawid Frycki boost::system::error_code ec;
73025e85c79SJae Hyun Yoo int i2cRetryCnt = 0;
731a642a948SDawid Frycki
73225e85c79SJae Hyun Yoo for (; i2cRetryCnt < ipmbI2cNumberOfRetries; i2cRetryCnt++)
733a642a948SDawid Frycki {
7340736e213SMatt Simmering boost::asio::async_write(i2cTargetDescriptor,
73537a7eaceSVijay Khemka boost::asio::buffer(buffer), yield[ec]);
736a642a948SDawid Frycki
737a642a948SDawid Frycki if (ec)
738a642a948SDawid Frycki {
73925e85c79SJae Hyun Yoo continue; // retry
740a642a948SDawid Frycki }
741a642a948SDawid Frycki break;
742a642a948SDawid Frycki }
743a642a948SDawid Frycki
74425e85c79SJae Hyun Yoo if (i2cRetryCnt == ipmbI2cNumberOfRetries)
74525e85c79SJae Hyun Yoo {
746bbfd00abSQiang XU std::string msgToLog =
747bbfd00abSQiang XU "requestAdd: Sent to I2C failed after retries."
748bbfd00abSQiang XU " busId=" +
749bbfd00abSQiang XU std::to_string(ipmbBusId) + ", error=" + ec.message();
75025e85c79SJae Hyun Yoo phosphor::logging::log<phosphor::logging::level::INFO>(
751bbfd00abSQiang XU msgToLog.c_str());
75225e85c79SJae Hyun Yoo }
75325e85c79SJae Hyun Yoo
754a642a948SDawid Frycki request->timer->expires_after(
755a642a948SDawid Frycki std::chrono::milliseconds(ipmbRequestRetryTimeout));
756a642a948SDawid Frycki request->timer->async_wait(yield[ec]);
757a642a948SDawid Frycki
758a642a948SDawid Frycki if (ec && ec != boost::asio::error::operation_aborted)
759a642a948SDawid Frycki {
760a642a948SDawid Frycki // unexpected error - invalidate request and return generic error
761a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
762a642a948SDawid Frycki "requestAdd: async_wait error");
763a642a948SDawid Frycki makeRequestInvalid(*request);
764a642a948SDawid Frycki return returnStatus(ipmbResponseStatus::error);
765a642a948SDawid Frycki }
766a642a948SDawid Frycki
767a642a948SDawid Frycki if (request->state == ipmbRequestState::matched)
768a642a948SDawid Frycki {
769a642a948SDawid Frycki // matched response, send it to client application
770a642a948SDawid Frycki makeRequestInvalid(*request);
771a642a948SDawid Frycki return request->returnMatchedResponse();
772a642a948SDawid Frycki }
773a642a948SDawid Frycki }
774a642a948SDawid Frycki
775a642a948SDawid Frycki makeRequestInvalid(*request);
776a642a948SDawid Frycki return returnStatus(ipmbResponseStatus::timeout);
777a642a948SDawid Frycki }
778a642a948SDawid Frycki
getChannel(uint8_t reqChannel)779950a2e81SKumar Thangavel static IpmbChannel* getChannel(uint8_t reqChannel)
780a642a948SDawid Frycki {
781*9898d612SPatrick Williams auto channel =
782*9898d612SPatrick Williams std::find_if(ipmbChannels.begin(), ipmbChannels.end(),
783950a2e81SKumar Thangavel [reqChannel](IpmbChannel& channel) {
784950a2e81SKumar Thangavel return channel.getChannelIdx() == reqChannel;
785a642a948SDawid Frycki });
786a642a948SDawid Frycki if (channel != ipmbChannels.end())
787a642a948SDawid Frycki {
788a642a948SDawid Frycki return &(*channel);
789a642a948SDawid Frycki }
790a642a948SDawid Frycki
791a642a948SDawid Frycki return nullptr;
792a642a948SDawid Frycki }
793a642a948SDawid Frycki
initializeChannels()794a642a948SDawid Frycki static int initializeChannels()
795a642a948SDawid Frycki {
796a642a948SDawid Frycki std::shared_ptr<IpmbCommandFilter> commandFilter =
797a642a948SDawid Frycki std::make_shared<IpmbCommandFilter>();
798a642a948SDawid Frycki
799314862d9SAmithash Prasad constexpr const char* configFilePath =
800314862d9SAmithash Prasad "/usr/share/ipmbbridge/ipmb-channels.json";
801314862d9SAmithash Prasad std::ifstream configFile(configFilePath);
802314862d9SAmithash Prasad if (!configFile.is_open())
803a642a948SDawid Frycki {
804314862d9SAmithash Prasad phosphor::logging::log<phosphor::logging::level::ERR>(
805314862d9SAmithash Prasad "initializeChannels: Cannot open config path");
806314862d9SAmithash Prasad return -1;
807314862d9SAmithash Prasad }
808314862d9SAmithash Prasad try
809314862d9SAmithash Prasad {
810950a2e81SKumar Thangavel uint8_t devIndex = 0;
811314862d9SAmithash Prasad auto data = nlohmann::json::parse(configFile, nullptr);
812314862d9SAmithash Prasad for (const auto& channelConfig : data["channels"])
813314862d9SAmithash Prasad {
814314862d9SAmithash Prasad const std::string& typeConfig = channelConfig["type"];
8150736e213SMatt Simmering const std::string& targetPath = channelConfig["slave-path"];
816314862d9SAmithash Prasad uint8_t bmcAddr = channelConfig["bmc-addr"];
817314862d9SAmithash Prasad uint8_t reqAddr = channelConfig["remote-addr"];
818950a2e81SKumar Thangavel
819314862d9SAmithash Prasad ipmbChannelType type = ipmbChannelTypeMap.at(typeConfig);
820a642a948SDawid Frycki
821950a2e81SKumar Thangavel if (channelConfig.contains("devIndex"))
822950a2e81SKumar Thangavel {
823950a2e81SKumar Thangavel devIndex = channelConfig["devIndex"];
824950a2e81SKumar Thangavel }
825950a2e81SKumar Thangavel
826950a2e81SKumar Thangavel auto channel = ipmbChannels.emplace(
827950a2e81SKumar Thangavel ipmbChannels.end(), io, bmcAddr, reqAddr,
828950a2e81SKumar Thangavel ((devIndex << 2) | static_cast<uint8_t>(type)), commandFilter);
8290736e213SMatt Simmering if (channel->ipmbChannelInit(targetPath.c_str()) < 0)
830a642a948SDawid Frycki {
831a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
832a642a948SDawid Frycki "initializeChannels: channel initialization failed");
833a642a948SDawid Frycki return -1;
834a642a948SDawid Frycki }
835a642a948SDawid Frycki }
836314862d9SAmithash Prasad }
837c0dd70d8SPatrick Williams catch (const nlohmann::json::exception& e)
838314862d9SAmithash Prasad {
839314862d9SAmithash Prasad phosphor::logging::log<phosphor::logging::level::ERR>(
840314862d9SAmithash Prasad "initializeChannels: Error parsing config file");
841314862d9SAmithash Prasad return -1;
842314862d9SAmithash Prasad }
843c0dd70d8SPatrick Williams catch (const std::out_of_range& e)
844314862d9SAmithash Prasad {
845314862d9SAmithash Prasad phosphor::logging::log<phosphor::logging::level::ERR>(
846314862d9SAmithash Prasad "initializeChannels: Error invalid type");
847314862d9SAmithash Prasad return -1;
848314862d9SAmithash Prasad }
849a642a948SDawid Frycki return 0;
850a642a948SDawid Frycki }
851a642a948SDawid Frycki
852*9898d612SPatrick Williams auto ipmbHandleRequest =
853*9898d612SPatrick Williams [](boost::asio::yield_context yield, uint8_t reqChannel, uint8_t netfn,
__anon377db2e00702(boost::asio::yield_context yield, uint8_t reqChannel, uint8_t netfn, uint8_t lun, uint8_t cmd, std::vector<uint8_t> dataReceived) 854*9898d612SPatrick Williams uint8_t lun, uint8_t cmd, std::vector<uint8_t> dataReceived) {
855950a2e81SKumar Thangavel IpmbChannel* channel = getChannel(reqChannel);
856950a2e81SKumar Thangavel
857a642a948SDawid Frycki if (channel == nullptr)
858a642a948SDawid Frycki {
859a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
860a642a948SDawid Frycki "ipmbHandleRequest: requested channel does not exist");
861a642a948SDawid Frycki return returnStatus(ipmbResponseStatus::invalid_param);
862a642a948SDawid Frycki }
863a642a948SDawid Frycki
864a642a948SDawid Frycki // check outstanding request list for valid sequence number
865a642a948SDawid Frycki uint8_t seqNum = 0;
866a642a948SDawid Frycki bool seqValid = channel->seqNumGet(seqNum);
867a642a948SDawid Frycki if (!seqValid)
868a642a948SDawid Frycki {
869a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::WARNING>(
870a642a948SDawid Frycki "ipmbHandleRequest: cannot add more requests to the list");
871a642a948SDawid Frycki return returnStatus(ipmbResponseStatus::busy);
872a642a948SDawid Frycki }
873a642a948SDawid Frycki
8740736e213SMatt Simmering uint8_t bmcTargetAddress = channel->getBmcTargetAddress();
8750736e213SMatt Simmering uint8_t rqTargetAddress = channel->getRqTargetAddress();
876a642a948SDawid Frycki
877a642a948SDawid Frycki // construct the request to add it to outstanding request list
878a642a948SDawid Frycki std::shared_ptr<IpmbRequest> request = std::make_shared<IpmbRequest>(
879*9898d612SPatrick Williams rqTargetAddress, netfn, ipmbRsLun, bmcTargetAddress, seqNum, lun,
880*9898d612SPatrick Williams cmd, dataReceived);
881a642a948SDawid Frycki
882a642a948SDawid Frycki if (!request->timer)
883a642a948SDawid Frycki {
884a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
885a642a948SDawid Frycki "ipmbHandleRequest: timer object does not exist");
886a642a948SDawid Frycki return returnStatus(ipmbResponseStatus::error);
887a642a948SDawid Frycki }
888a642a948SDawid Frycki
889a642a948SDawid Frycki return channel->requestAdd(yield, request);
890a642a948SDawid Frycki };
891a642a948SDawid Frycki
addUpdateTargetAddrHandler()8920736e213SMatt Simmering void addUpdateTargetAddrHandler()
8938edcf1a0SQiang XU {
8940736e213SMatt Simmering // callback to handle dbus signal of updating target addr
8950736e213SMatt Simmering std::function<void(sdbusplus::message_t&)> updateTargetAddrHandler =
8963852f8ecSPatrick Williams [](sdbusplus::message_t& message) {
8970736e213SMatt Simmering uint8_t reqChannel, busId, targetAddr;
8988edcf1a0SQiang XU
8998edcf1a0SQiang XU // valid source of signal, check whether from multi-node manager
9008edcf1a0SQiang XU std::string pathName = message.get_path();
9018edcf1a0SQiang XU if (pathName != "/xyz/openbmc_project/MultiNode/Status")
9028edcf1a0SQiang XU {
9038edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
9040736e213SMatt Simmering "addUpdateTargetAddrHandler: invalid obj path");
9058edcf1a0SQiang XU return;
9068edcf1a0SQiang XU }
9078edcf1a0SQiang XU
9080736e213SMatt Simmering message.read(reqChannel, busId, targetAddr);
9098edcf1a0SQiang XU
910950a2e81SKumar Thangavel IpmbChannel* channel = getChannel(reqChannel);
911950a2e81SKumar Thangavel
9128edcf1a0SQiang XU if (channel == nullptr ||
913950a2e81SKumar Thangavel channel->getChannelType() != ipmbChannelType::ipmb)
9148edcf1a0SQiang XU {
9158edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
9160736e213SMatt Simmering "addUpdateTargetAddrHandler: invalid channel");
9178edcf1a0SQiang XU return;
9188edcf1a0SQiang XU }
9198edcf1a0SQiang XU if (busId != channel->getBusId())
9208edcf1a0SQiang XU {
9218edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
9220736e213SMatt Simmering "addUpdateTargetAddrHandler: invalid busId");
9238edcf1a0SQiang XU return;
9248edcf1a0SQiang XU }
9250736e213SMatt Simmering if (channel->getBmcTargetAddress() == targetAddr)
9268edcf1a0SQiang XU {
9278edcf1a0SQiang XU phosphor::logging::log<phosphor::logging::level::INFO>(
9280736e213SMatt Simmering "addUpdateTargetAddrHandler: channel bmc target addr is "
9298edcf1a0SQiang XU "unchanged, do nothing");
9308edcf1a0SQiang XU return;
9318edcf1a0SQiang XU }
9328edcf1a0SQiang XU
9330736e213SMatt Simmering channel->ipmbChannelUpdateTargetAddress(targetAddr);
9348edcf1a0SQiang XU };
9358edcf1a0SQiang XU
9363852f8ecSPatrick Williams static auto match = std::make_unique<sdbusplus::bus::match_t>(
9373852f8ecSPatrick Williams static_cast<sdbusplus::bus_t&>(*conn),
9380736e213SMatt Simmering "type='signal',member='updateBmcSlaveAddr',", updateTargetAddrHandler);
9398edcf1a0SQiang XU }
9408edcf1a0SQiang XU
addSendBroadcastHandler()941bbfd00abSQiang XU void addSendBroadcastHandler()
942bbfd00abSQiang XU {
943bbfd00abSQiang XU // callback to handle dbus signal of sending broadcast message
9443852f8ecSPatrick Williams std::function<void(sdbusplus::message_t&)> sendBroadcastHandler =
9453852f8ecSPatrick Williams [](sdbusplus::message_t& message) {
946bbfd00abSQiang XU uint8_t reqChannel, netFn, lun, cmd;
947bbfd00abSQiang XU std::vector<uint8_t> dataReceived;
948bbfd00abSQiang XU message.read(reqChannel, netFn, lun, cmd, dataReceived);
949bbfd00abSQiang XU
950950a2e81SKumar Thangavel IpmbChannel* channel = getChannel(reqChannel);
951950a2e81SKumar Thangavel
952bbfd00abSQiang XU if (channel == nullptr)
953bbfd00abSQiang XU {
954bbfd00abSQiang XU phosphor::logging::log<phosphor::logging::level::ERR>(
955bbfd00abSQiang XU "addSendBroadcastMsgHandler: requested channel does not "
956bbfd00abSQiang XU "exist");
957bbfd00abSQiang XU return;
958bbfd00abSQiang XU }
959bbfd00abSQiang XU
9600736e213SMatt Simmering uint8_t bmcTargetAddress = channel->getBmcTargetAddress();
961bbfd00abSQiang XU uint8_t seqNum = 0; // seqNum is not used in broadcast msg
962bbfd00abSQiang XU uint8_t targetAddr = broadcastAddress;
963bbfd00abSQiang XU
964*9898d612SPatrick Williams std::shared_ptr<IpmbRequest> request =
965*9898d612SPatrick Williams std::make_shared<IpmbRequest>(targetAddr, netFn, ipmbRsLun,
966*9898d612SPatrick Williams bmcTargetAddress, seqNum, lun,
967*9898d612SPatrick Williams cmd, dataReceived);
968bbfd00abSQiang XU
969bbfd00abSQiang XU std::shared_ptr<std::vector<uint8_t>> buffer =
970bbfd00abSQiang XU std::make_shared<std::vector<uint8_t>>();
971bbfd00abSQiang XU
972bbfd00abSQiang XU if (request->ipmbToi2cConstruct(*buffer) != 0)
973bbfd00abSQiang XU {
974bbfd00abSQiang XU return;
975bbfd00abSQiang XU }
976bbfd00abSQiang XU
977bbfd00abSQiang XU channel->ipmbSendI2cFrame(buffer);
978bbfd00abSQiang XU };
979bbfd00abSQiang XU
9803852f8ecSPatrick Williams static auto match = std::make_unique<sdbusplus::bus::match_t>(
9813852f8ecSPatrick Williams static_cast<sdbusplus::bus_t&>(*conn),
982bbfd00abSQiang XU "type='signal',member='sendBroadcast',", sendBroadcastHandler);
983bbfd00abSQiang XU }
984bbfd00abSQiang XU
985a642a948SDawid Frycki /**
986a642a948SDawid Frycki * @brief Main
987a642a948SDawid Frycki */
main()988825ad836SPatrick Williams int main()
989a642a948SDawid Frycki {
990a642a948SDawid Frycki conn->request_name(ipmbBus);
991a642a948SDawid Frycki
992a642a948SDawid Frycki auto server = sdbusplus::asio::object_server(conn);
993a642a948SDawid Frycki
994a642a948SDawid Frycki std::shared_ptr<sdbusplus::asio::dbus_interface> ipmbIface =
995a642a948SDawid Frycki server.add_interface(ipmbObj, ipmbDbusIntf);
996a642a948SDawid Frycki
997a642a948SDawid Frycki ipmbIface->register_method("sendRequest", std::move(ipmbHandleRequest));
998a642a948SDawid Frycki ipmbIface->initialize();
999a642a948SDawid Frycki
1000a642a948SDawid Frycki if (initializeChannels() < 0)
1001a642a948SDawid Frycki {
1002a642a948SDawid Frycki phosphor::logging::log<phosphor::logging::level::ERR>(
1003a642a948SDawid Frycki "Error initializeChannels");
1004a642a948SDawid Frycki return -1;
1005a642a948SDawid Frycki }
1006a642a948SDawid Frycki
10070736e213SMatt Simmering addUpdateTargetAddrHandler();
10088edcf1a0SQiang XU
1009bbfd00abSQiang XU addSendBroadcastHandler();
1010bbfd00abSQiang XU
1011a642a948SDawid Frycki io.run();
1012a642a948SDawid Frycki return 0;
1013a642a948SDawid Frycki }
1014