phosphor-ipmi-ipmb

目录

代码分析

配置IPMB功能

 在设备树中配置:

在menuconfig中进行配置   

配置ipmb-channels.json文件


代码分析

在ipmbbridged.cpp文件main函数下,我们通过以下代码对函数实现的方法进行进行了注册,该方法的回调函数为 “ipmbHandleRequest”。

    conn->request_name(ipmbBus);

    auto server = sdbusplus::asio::object_server(conn);

    std::shared_ptr ipmbIface =
        server.add_interface(ipmbObj, ipmbDbusIntf);

    ipmbIface->register_method("sendRequest", std::move(ipmbHandleRequest));
    ipmbIface->initialize();

接着,通过initializeChannels函数对模块进行了初始化。该函数是读取/usr/share/ipmbbridge/ipmb-channels.json文件的内容来进行对class IpmbChannel 进行构造。

通过下面代码,可以看到,在/dev/ipmb-N得到新的数据时,将会调用processI2cEvent()函数来进行处理。

    i2cSlaveDescriptor.assign(ipmbi2cSlaveFd);

    i2cSlaveDescriptor.async_wait(
        boost::asio::posix::descriptor_base::wait_read,
        [this](const boost::system::error_code &ec) {
            if (ec)
            {
                phosphor::logging::log(
                    "Error: processI2cEvent()");
                return;
            }

            processI2cEvent();
        });

        通过对processI2cEvent函数的分析,可以看到该函数会对接收到的报文进行各种解析,包括接收到报文字节的长度,报文头是否正确等等。当从机是在向openbmc回复应答报文时,该报文是通过以下case进行返回的。

        

    // copy frame to ipmib message buffer
    if (ipmbIsResponse(ipmbFrame))
    {
        std::unique_ptr ipmbMessageReceived =
            std::make_unique();

        ipmbMessageReceived->i2cToIpmbConstruct(ipmbFrame, r);

        // try to match response with outstanding request
        responseMatch(ipmbMessageReceived);
    }

如果是其他板卡向openbmc发送报文时,则是通过以下代码。分析该代码可知,在判定netfn与cmd合法之后,报文将送到phoshpor-ipmi-host中对应的函数中进行处理。

 // if command is blocked - respond with 'invalid command'
        // completion code
        if (commandFilter)
        {
            uint8_t netFn = ipmbNetFnGet(ipmbFrame->Header.Req.rsNetFnLUN);
            uint8_t cmd = ipmbFrame->Header.Req.cmd;
            uint8_t rqSA = ipmbFrame->Header.Req.rqSA;

            if (commandFilter->isBlocked(netFn, cmd))
            {
                uint8_t seq = ipmbSeqGet(ipmbFrame->Header.Req.rqSeqLUN);
                uint8_t lun =
                    ipmbLunFromSeqLunGet(ipmbFrame->Header.Req.rqSeqLUN);

                // prepare generic response
                auto ipmbResponse = IpmbResponse(
                    rqSA, ipmbRespNetFn(netFn), lun, ipmbBmcSlaveAddress, seq,
                    ipmbRsLun, cmd, ipmbIpmiInvalidCmd, {});

                auto buffer = ipmbResponse.ipmbToi2cConstruct();
                if (buffer)
                {
                    ipmbSendI2cFrame(buffer);
                }

                goto end;
            }
        }

        auto ipmbMessageReceived = IpmbRequest();
        ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);

        int devId = getDevIndex();

        std::map> options{
            {"rqSA", ipmbAddressTo7BitSet(ipmbMessageReceived.rqSA)},
            {"hostId", devId}};

        using IpmiDbusRspType = std::tuple>;
        conn->async_method_call(
            [this, rqLun{ipmbMessageReceived.rqLun},
             seq{ipmbMessageReceived.seq}, address{ipmbMessageReceived.rqSA}](
                const boost::system::error_code &ec,
                const IpmiDbusRspType &response) {
                const auto &[netfn, lun, cmd, cc, payload] = response;
                if (ec)
                {
                    phosphor::logging::log(
                        "processI2cEvent: error getting response from IPMI");
                    return;
                }

                uint8_t bmcSlaveAddress = getBmcSlaveAddress();

                if (payload.size() > ipmbMaxDataSize)
                {
                    phosphor::logging::log(
                        "processI2cEvent: response exceeding maximum size");

                    // prepare generic response
                    auto ipmbResponse = IpmbResponse(
                        address, netfn, rqLun, bmcSlaveAddress, seq, ipmbRsLun,
                        cmd, ipmbIpmiCmdRespNotProvided, {});

                    auto buffer = ipmbResponse.ipmbToi2cConstruct();
                    if (buffer)
                    {
                        ipmbSendI2cFrame(buffer);
                    }

                    return;
                }

                if (!(netfn & ipmbNetFnResponseMask))
                {
                    // we are not expecting request here
                    phosphor::logging::log(
                        "processI2cEvent: got a request instead of response");
                    return;
                }

                // if command is not supported, add it to filter
                if (cc == ipmbIpmiInvalidCmd)
                {
                    addFilter(ipmbReqNetFnFromRespNetFn(netfn), cmd);
                }

                // payload is empty after constructor invocation
                auto ipmbResponse =
                    IpmbResponse(address, netfn, rqLun, bmcSlaveAddress, seq,
                                 lun, cmd, cc, payload);

                auto buffer = ipmbResponse.ipmbToi2cConstruct();
                if (!buffer)
                {
                    phosphor::logging::log(
                        "processI2cEvent: error constructing a request");
                    return;
                }

                ipmbSendI2cFrame(buffer);
            },
            "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
            "xyz.openbmc_project.Ipmi.Server", "execute",
            ipmbMessageReceived.netFn, ipmbMessageReceived.rsLun,
            ipmbMessageReceived.cmd, ipmbMessageReceived.data, options);
    }

在函数ipmbHandleRequest中,我们是进行将报文发送,并对processI2cEvent处理之后的结果进行分析,如果报文分析正常的话,我们将通过以下代码将子板中的数据返回至方法调用处。

        if (request->state == ipmbRequestState::matched)
        {
            // matched response, send it to client application
            makeRequestInvalid(*request);
            return request->returnMatchedResponse();
        }

我是在phosphor-ipmi-host中对该方法进行的调用,具体调用代码如下:

int sendIpmbCmd(uint8_t netFn, uint8_t cmd, uint8_t bicAddr,
               std::vector& cmdData, std::vector& respData)
{
    static constexpr uint8_t lun = 0;

    auto bus = getSdBus();

    auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
                                       "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
                                       "org.openbmc.Ipmb", "sendRequest");
    method.append(bicAddr, netFn, lun, cmd, cmdData);

    auto reply = bus->call(method);
    if (reply.is_method_error())
    {
        phosphor::logging::log(
            "Error reading from BIC");
        return -1;
    }

    IpmbMethodType resp;
    reply.read(resp);

    respData =
        std::move(std::get>(resp));

    return 0;
}

配置IPMB功能

 在设备树中配置:


&i2c1 {
    /* PCIe slot 2 (x16) */
    status = "okay";
    multi-master;
    ipmb1@10 {                                                                                                                                                                                            
        compatible = "ipmb-dev";
        reg = <0x10 | I2C_OWM_SLAVE_ADDRESS>;
        i2c-protocol;
    };
};

   其中openbmc中i2C的从机地址为0x10,该从机地址可以通过devmem 0x1e78a058进行查看

在menuconfig中进行配置   

键入命令:bitbake linux-aspeed -c menuconfig

按下“/” 并键入ipmb进行查看。

在device driver 下进入character device 将IPMI top-level message handler进行勾选,将IPMB Interface handler 进行勾选

保存退出即可;

配置ipmb-channels.json文件

{                                                                                                                                                                                                         
  "channels": [
    {
      "type": "me",
      "slave-path": "/dev/ipmb-1",
      "bmc-addr": 32,
      "remote-addr": 176
    }
  ]
}

remote-addr为子板卡  (从机地址 << 1);

你可能感兴趣的:(openbmc,ipmb,ipmi,c++,bmc)