1、背景介绍
目前板上有x86和bmc,bmc通过gpio进行控灯,x86和bmc之间通过lpc总线连接,示意图如下:
这里BMC采用Pentail提供的解决方案,芯片为smartfusion。X86采用Intel E5V4芯片,上面运行Redhat操作系统。
2、方法介绍
目前linux提供了open ipmi驱动和ipmitool来实现X86与BMC交互,安装完驱动后使用ipmitool可以获取BMC的状态,相关命令参考如下:https://docs.oracle.com/cd/E40705_01/html/E40351/z400000c1016683.html
可以执行ipmitool raw +自定义的netfn和cmd给BMC发命令,BMC收到ipmi命令后根据netfn和cmd进行闪灯即可。
一种方法是直接使用system("ipmitool raw xx xx"),不过使用system系统函数会创建线程,对系统性能造成影响。另一种方法就是根据ipmitool中提供的源码进行个性化修改,具体如下。
3、自定义闪灯
通过查阅代码可以发现执行Ipmitool raw使用的是open.c和open.h这两个文件中的函数。于是可以修改这两个文件,如下:
led.h
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
int led_open();
void led_close();
int led_trigger(int index);
int led_on(int index);
int led_off(int index);
led.c
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#define _POSIX_C_SOURCE 1
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "led.h"
#define IPMI_BMC_CHANNEL 0xf
#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c
struct ipmi_msg {
unsigned char netfn;
unsigned char cmd;
unsigned short data_len;
unsigned char *data;
};
struct ipmi_req {
unsigned char *addr;
unsigned int addr_len;
long msgid;
struct ipmi_msg msg;
};
struct ipmi_system_interface_addr {
int addr_type;
short channel;
unsigned char lun;
};
#define IPMI_IOC_MAGIC 'i'
#define IPMICTL_SEND_COMMAND _IOR(IPMI_IOC_MAGIC, 13, struct ipmi_req)
int fd=-1;
int led_open()
{
fd=open("/dev/ipmi0", O_RDWR);
if(fd<0)
{
printf("open ipmidev failed\n");
return -1;
}
return fd;
}
void led_close()
{
if (fd >= 0)
{
close(fd);
}
}
int ledA_trigger()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=2;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x18;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledB_trigger()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=2;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x20;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledC_trigger()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=2;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x14;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledD_trigger()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=2;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x16;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int led_trigger(int index)
{
if(index==0)
{
ledA_trigger();
}
else if(index==1)
{
ledB_trigger();
}
else if(index==2)
{
ledC_trigger();
}
else if(index==3)
{
ledD_trigger();
}
else
{
printf("index invalid 0-3 is ok\n");
}
}
int ledA_on()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=1;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x18;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledB_on()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=1;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x20;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledC_on()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=1;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x14;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledD_on()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=1;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x16;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int led_on(int index)
{
if(index==0)
{
ledA_on();
}
else if(index==1)
{
ledB_on();
}
else if(index==2)
{
ledC_on();
}
else if(index==3)
{
ledD_on();
}
else
{
printf("index invalid 0-3 is ok\n");
}
}
int ledA_off()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=0;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x18;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledB_off()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=0;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x20;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledC_off()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=0;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x14;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int ledD_off()
{
struct ipmi_system_interface_addr bmc_addr = {
.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
.channel = IPMI_BMC_CHANNEL,
};
struct ipmi_req _req;
char dd[2];
dd[0]=0;
memset(&_req, 0, sizeof(struct ipmi_req));
bmc_addr.lun =0;
_req.addr = (unsigned char *) &bmc_addr;
_req.addr_len = sizeof(bmc_addr);
_req.msgid = 0;
_req.msg.data = dd;
_req.msg.data_len = 0x1;
_req.msg.netfn =0x6;
_req.msg.cmd =0x16;
if(ioctl(fd, IPMICTL_SEND_COMMAND, &_req) < 0)
{
printf( "Unable to send command\n");
return -1;
}
return 1;
}
int led_off(int index)
{
if(index==0)
{
ledA_off();
}
else if(index==1)
{
ledB_off();
}
else if(index==2)
{
ledC_off();
}
else if(index==3)
{
ledD_off();
}
else
{
printf("index invalid 0-3 is ok\n");
}
}
调用接口如下
/*
============================================================================
Name : led_example.c
Author : 123
Version :
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include
#include
#include "led.h"
int main(void) {
led_open();
led_on(0);
led_on(1);
led_on(2);
led_on(3);
sleep(2);
led_off(0);
led_off(1);
led_off(2);
led_off(3);
sleep(2);
led_trigger(0);
led_trigger(1);
led_trigger(2);
led_trigger(3);
sleep(2);
led_trigger(0);
led_trigger(1);
led_trigger(2);
led_trigger(3);
led_close();
return EXIT_SUCCESS;
}
这样就能直接控灯了。