IPMI的全称是Intelligent Platform Management Interface,是一个用于监控系统的智能设备,其能动态的检测到系统中的传感器并有监控这些传感器工作的能力,当这些传感器的工作异常是能通知系统.IPMI的controller就叫BMC,其全称是Baseboard Management Controller.
我们这里以si_intf.c 为例,其本身就是就是和BMC 通信的。
{
int i;
char *str;
int rv;
struct smi_info *e;
enum ipmi_addr_src type = SI_INVALID;
// 避免重复初始化,可以理解为简单的单例模式
if (initialized)
return 0;
initialized = 1;
//ipmi controller 可以挂在platform/pci等个个总线上,这里以platform为例.
if (si_tryplatform) {
rv = platform_driver_register(&ipmi_driver);
if (rv) {
printk(KERN_ERR PFX "Unable to register "
"driver: %d\n", rv);
return rv;
}
}
//这里的si_type_str的值有三种SI_KCS/SI_SMIC/SI_BT
/* Parse out the si_type string into its components. */
str = si_type_str;
if (*str != '\0') {
for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) {
si_type[i] = str;
str = strchr(str, ',');
if (str) {
*str = '\0';
str++;
} else {
break;
}
}
}
printk(KERN_INFO "IPMI System Interface driver.\n");
//通过hardcode的方式检测是否有BMC,如果没有BMC,也就没有必要往下走了,因为我们这个程序本身就是和BMC 通信的
/* If the user gave us a device, they presumably want us to use it */
if (!hardcode_find_bmc())
return 0;
//这里检测IPMI是否是pci设备
#ifdef CONFIG_PCI
if (si_trypci) {
rv = pci_register_driver(&ipmi_pci_driver);
if (rv)
printk(KERN_ERR PFX "Unable to register "
"PCI driver: %d\n", rv);
else
pci_registered = true;
}
#endif
//检测是否通过DMI告知bmc的信息
#ifdef CONFIG_DMI
if (si_trydmi)
dmi_find_bmc();
#endif
//检测是否通过ACPI告知bmc的信息
#ifdef CONFIG_ACPI
if (si_tryacpi)
spmi_find_bmc();
#endif
#ifdef CONFIG_PARISC
register_parisc_driver(&ipmi_parisc_driver);
parisc_registered = true;
#endif
/* We prefer devices with interrupts, but in the case of a machine
with multiple BMCs we assume that there will be several instances
of a given type so if we succeed in registering a type then also
try to register everything else of the same type */
//这里针对有多个BMC的情况,一般不会走这里
mutex_lock(&smi_infos_lock);
list_for_each_entry(e, &smi_infos, link) {
/* Try to register a device if it has an IRQ and we either
haven't successfully registered a device yet or this
device has the same type as one we successfully registered */
if (e->irq && (!type || e->addr_source == type)) {
if (!try_smi_init(e)) {
type = e->addr_source;
}
}
}
/* type will only have been set if we successfully registered an si */
if (type) {
mutex_unlock(&smi_infos_lock);
return 0;
}
/* Fall back to the preferred device */
//针对smi_infos list上合法的smi_info 调用try_smi_init 继续初始化.
list_for_each_entry(e, &smi_infos, link) {
if (!e->irq && (!type || e->addr_source == type)) {
if (!try_smi_init(e)) {
type = e->addr_source;
}
}
}
mutex_unlock(&smi_infos_lock);
if (type)
return 0;
mutex_lock(&smi_infos_lock);
if (unload_when_empty && list_empty(&smi_infos)) {
mutex_unlock(&smi_infos_lock);
cleanup_ipmi_si();
printk(KERN_WARNING PFX
"Unable to find any System Interface(s)\n");
return -ENODEV;
} else {
mutex_unlock(&smi_infos_lock);
return 0;
}
}
module_init(init_ipmi_si);
总的来说ipmi driver是和BMC通信的interface。在init_ipmi_si中先判断ipmi是挂在哪种总线上,可以选的总线有platform/pci。然后字符串si_type_str 中判断si_type,可以选的有三种SI_KCS/SI_SMIC/SI_BT,然后再以hardcode的方式检测是否有BMC,如果有的话,在分别通过DMI/ACPI来查看bmc的信息。最后针对smi_infos 合法的smi_info调用调用try_smi_init 继续初始化.
下来看看如果通过hardcode的方式发现BMC的
static int hardcode_find_bmc(void)
{
int ret = -ENODEV;
int i;
struct smi_info *info;
for (i = 0; i < SI_MAX_PARMS; i++) {
if (!ports[i] && !addrs[i])
continue;
info = smi_info_alloc();
if (!info)
return -ENOMEM;
info->addr_source = SI_HARDCODED;
printk(KERN_INFO PFX "probing via hardcoded address\n");
if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
info->si_type = SI_KCS;
} else if (strcmp(si_type[i], "smic") == 0) {
info->si_type = SI_SMIC;
} else if (strcmp(si_type[i], "bt") == 0) {
info->si_type = SI_BT;
} else {
printk(KERN_WARNING PFX "Interface type specified "
"for interface %d, was invalid: %s\n",
i, si_type[i]);
kfree(info);
continue;
}
if (ports[i]) {
/* An I/O port */
info->io_setup = port_setup;
info->io.addr_data = ports[i];
info->io.addr_type = IPMI_IO_ADDR_SPACE;
} else if (addrs[i]) {
/* A memory port */
info->io_setup = mem_setup;
info->io.addr_data = addrs[i];
info->io.addr_type = IPMI_MEM_ADDR_SPACE;
} else {
printk(KERN_WARNING PFX "Interface type specified "
"for interface %d, but port and address were "
"not set or set to zero.\n", i);
kfree(info);
continue;
}
info->io.addr = NULL;
info->io.regspacing = regspacings[i];
if (!info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = regsizes[i];
if (!info->io.regsize)
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[i];
info->irq = irqs[i];
if (info->irq)
info->irq_setup = std_irq_setup;
info->slave_addr = slave_addrs[i];
//前面都是按照和BMC通讯的协议赋值,重点是add_smi 返回0,调用try_smi_init来发现BMC的
if (!add_smi(info)) {
if (try_smi_init(info))
cleanup_one_si(info);
ret = 0;
} else {
kfree(info);
}
}
return ret;
}
static int add_smi(struct smi_info *new_smi)
{
int rv = 0;
printk(KERN_INFO PFX "Adding %s-specified %s state machine",
ipmi_addr_src_to_str(new_smi->addr_source),
si_to_str[new_smi->si_type]);
mutex_lock(&smi_infos_lock);
if (!is_new_interface(new_smi)) {
printk(KERN_CONT " duplicate interface\n");
rv = -EBUSY;
goto out_err;
}
printk(KERN_CONT "\n");
/* So we know not to free it unless we have allocated one. */
new_smi->intf = NULL;
new_smi->si_sm = NULL;
new_smi->handlers = NULL;
list_add_tail(&new_smi->link, &smi_infos);
out_err:
mutex_unlock(&smi_infos_lock);
return rv;
}
由于是第一次,所以is_new_interface 返回1,因此在add_smi中最终返回0,并把smi_info *new_smi 添加到smi_infos lise中,从这里知道原来smi_infos 中的成员都是通过add_smi 添加的,在try_smi_init 中最终是通过
if (new_smi->handlers->detect(new_smi->si_sm)) {
if (new_smi->addr_source)
printk(KERN_INFO PFX "Interface detection failed\n");
rv = -ENODEV;
goto out_err;
}
来检测是否有BMC的。
我们这里以si_intf.c 为例,其本身就是就是和BMC 通信的。
先看实际IPMI 运行的截图,ipmi 有很多种命令。
{
int i;
char *str;
int rv;
struct smi_info *e;
enum ipmi_addr_src type = SI_INVALID;
// 避免重复初始化,可以理解为简单的单例模式
if (initialized)
return 0;
initialized = 1;
//ipmi controller 可以挂在platform/pci等个个总线上,这里以platform为例.
if (si_tryplatform) {
rv = platform_driver_register(&ipmi_driver);
if (rv) {
printk(KERN_ERR PFX "Unable to register "
"driver: %d\n", rv);
return rv;
}
}
//这里的si_type_str的值有三种SI_KCS/SI_SMIC/SI_BT
/* Parse out the si_type string into its components. */
str = si_type_str;
if (*str != '\0') {
for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) {
si_type[i] = str;
str = strchr(str, ',');
if (str) {
*str = '\0';
str++;
} else {
break;
}
}
}
printk(KERN_INFO "IPMI System Interface driver.\n");
//通过hardcode的方式检测是否有BMC,如果没有BMC,也就没有必要往下走了,因为我们这个程序本身就是和BMC 通信的
/* If the user gave us a device, they presumably want us to use it */
if (!hardcode_find_bmc())
return 0;
//这里检测IPMI是否是pci设备
#ifdef CONFIG_PCI
if (si_trypci) {
rv = pci_register_driver(&ipmi_pci_driver);
if (rv)
printk(KERN_ERR PFX "Unable to register "
"PCI driver: %d\n", rv);
else
pci_registered = true;
}
#endif
//检测是否通过DMI告知bmc的信息
#ifdef CONFIG_DMI
if (si_trydmi)
dmi_find_bmc();
#endif
//检测是否通过ACPI告知bmc的信息
#ifdef CONFIG_ACPI
if (si_tryacpi)
spmi_find_bmc();
#endif
#ifdef CONFIG_PARISC
register_parisc_driver(&ipmi_parisc_driver);
parisc_registered = true;
#endif
/* We prefer devices with interrupts, but in the case of a machine
with multiple BMCs we assume that there will be several instances
of a given type so if we succeed in registering a type then also
try to register everything else of the same type */
//这里针对有多个BMC的情况,一般不会走这里
mutex_lock(&smi_infos_lock);
list_for_each_entry(e, &smi_infos, link) {
/* Try to register a device if it has an IRQ and we either
haven't successfully registered a device yet or this
device has the same type as one we successfully registered */
if (e->irq && (!type || e->addr_source == type)) {
if (!try_smi_init(e)) {
type = e->addr_source;
}
}
}
/* type will only have been set if we successfully registered an si */
if (type) {
mutex_unlock(&smi_infos_lock);
return 0;
}
/* Fall back to the preferred device */
//针对smi_infos list上合法的smi_info 调用try_smi_init 继续初始化.
list_for_each_entry(e, &smi_infos, link) {
if (!e->irq && (!type || e->addr_source == type)) {
if (!try_smi_init(e)) {
type = e->addr_source;
}
}
}
mutex_unlock(&smi_infos_lock);
if (type)
return 0;
mutex_lock(&smi_infos_lock);
if (unload_when_empty && list_empty(&smi_infos)) {
mutex_unlock(&smi_infos_lock);
cleanup_ipmi_si();
printk(KERN_WARNING PFX
"Unable to find any System Interface(s)\n");
return -ENODEV;
} else {
mutex_unlock(&smi_infos_lock);
return 0;
}
}
module_init(init_ipmi_si);
总的来说ipmi driver是和BMC通信的interface。在init_ipmi_si中先判断ipmi是挂在哪种总线上,可以选的总线有platform/pci。然后字符串si_type_str 中判断si_type,可以选的有三种SI_KCS/SI_SMIC/SI_BT,然后再以hardcode的方式检测是否有BMC,如果有的话,在分别通过DMI/ACPI来查看bmc的信息。最后针对smi_infos 合法的smi_info调用调用try_smi_init 继续初始化.
下来看看如果通过hardcode的方式发现BMC的
static int hardcode_find_bmc(void)
{
int ret = -ENODEV;
int i;
struct smi_info *info;
for (i = 0; i < SI_MAX_PARMS; i++) {
if (!ports[i] && !addrs[i])
continue;
info = smi_info_alloc();
if (!info)
return -ENOMEM;
info->addr_source = SI_HARDCODED;
printk(KERN_INFO PFX "probing via hardcoded address\n");
if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
info->si_type = SI_KCS;
} else if (strcmp(si_type[i], "smic") == 0) {
info->si_type = SI_SMIC;
} else if (strcmp(si_type[i], "bt") == 0) {
info->si_type = SI_BT;
} else {
printk(KERN_WARNING PFX "Interface type specified "
"for interface %d, was invalid: %s\n",
i, si_type[i]);
kfree(info);
continue;
}
if (ports[i]) {
/* An I/O port */
info->io_setup = port_setup;
info->io.addr_data = ports[i];
info->io.addr_type = IPMI_IO_ADDR_SPACE;
} else if (addrs[i]) {
/* A memory port */
info->io_setup = mem_setup;
info->io.addr_data = addrs[i];
info->io.addr_type = IPMI_MEM_ADDR_SPACE;
} else {
printk(KERN_WARNING PFX "Interface type specified "
"for interface %d, but port and address were "
"not set or set to zero.\n", i);
kfree(info);
continue;
}
info->io.addr = NULL;
info->io.regspacing = regspacings[i];
if (!info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = regsizes[i];
if (!info->io.regsize)
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = regshifts[i];
info->irq = irqs[i];
if (info->irq)
info->irq_setup = std_irq_setup;
info->slave_addr = slave_addrs[i];
//前面都是按照和BMC通讯的协议赋值,重点是add_smi 返回0,调用try_smi_init来发现BMC的
if (!add_smi(info)) {
if (try_smi_init(info))
cleanup_one_si(info);
ret = 0;
} else {
kfree(info);
}
}
return ret;
}
static int add_smi(struct smi_info *new_smi)
{
int rv = 0;
printk(KERN_INFO PFX "Adding %s-specified %s state machine",
ipmi_addr_src_to_str(new_smi->addr_source),
si_to_str[new_smi->si_type]);
mutex_lock(&smi_infos_lock);
if (!is_new_interface(new_smi)) {
printk(KERN_CONT " duplicate interface\n");
rv = -EBUSY;
goto out_err;
}
printk(KERN_CONT "\n");
/* So we know not to free it unless we have allocated one. */
new_smi->intf = NULL;
new_smi->si_sm = NULL;
new_smi->handlers = NULL;
list_add_tail(&new_smi->link, &smi_infos);
out_err:
mutex_unlock(&smi_infos_lock);
return rv;
}
由于是第一次,所以is_new_interface 返回1,因此在add_smi中最终返回0,并把smi_info *new_smi 添加到smi_infos lise中,从这里知道原来smi_infos 中的成员都是通过add_smi 添加的,在try_smi_init 中最终是通过
if (new_smi->handlers->detect(new_smi->si_sm)) {
if (new_smi->addr_source)
printk(KERN_INFO PFX "Interface detection failed\n");
rv = -ENODEV;
goto out_err;
}
来检测是否有BMC的。