目录
1. IPMI概述
2. IPMI系统设计
3. 主BMC模块设计
5. 从IPMI模块设计
6. 名词解释
6. 代码
1. IPMI概述
智能平台管理接口(IPMI:Intelligent Platform Management Interface)是一项应用于服务器管理系统设计的标准,由Intel、HP、Dell和NEC公司共同提出。
1998 年IPMI 1.0 版提供的最初功能是能够通过网络监控组件温度和电压。IPMI 1.5 版在原有基础上添加了PCI 管理总线等功能,IPMI 2.0 在完全兼容IPMI 1.0 与IPMI 1.5 的情况下,该版本在上两个版本的基础上有了很多改进,新增了控制台的重定向的支持,对于远程管理方面,管理人员可以利用串口、网口远程管理服务器(包括开关机)。IPMI通过使用私有I2C总线或IPMB将附加的管理控制器连接至系统来提供对平台管理的扩展的支持。
在IPMI推出之前,每个计算机厂商都自行开发了监控其平台中各组件性能的方案,这些方案倾向于将一个企业或电信公司与某一具体厂商紧密结合,通常管理效率低下。随着数据中心计算设备和电信网络的激增,这种长期形成的缺点已经变得日益严重。
IPMI 提供了一种标准化方式以便监控计算设备运行时各组件的状况,特别适合对大量服务器控制的任务管理,同时它也适用于不同的操作系统。IPMI 还有一个显著特点在于其是独立于操作系统,决定了它不会像带内的软件管理,不用考虑所在操作系统的运行情况,或者由于一些未知原因出现的异常报错,IPMI 模块只要在不断电的情况下依然可以正常的运行工作。这是带外管理的显著优势。
当前最新版本为2.0。利用此接口标准设计有助于在不同类服务器系统硬件上实施系统管理。下图为典型的IPMI实现的管理检测系统。
2. IPMI系统设计
设备的IPMI分为主模块和从模块,其中IPMI的主模块可以放到CPU模块上,IPMI主模块通过IIC总线采集各个从模块的信息,通过网口统一上报给外部的监测设备。IPMI从模块负责采集各板卡的电流、电压、温度等信息,并收集从模块上CPU的信息。SHMC汇总整个系统的温度信息,根据温度信息控制整机的风扇速度。同时负责整个单元的状态监控、告警管理,日志管理,KVM over IP,CPU模块上的磁盘状态、内存状态及故障等功能。
3. 主BMC模块设计
主BMC模块主要用于组织和管理基于IPMI标准的硬件资源,由CPU板上的ChMC(机箱管理控制器)实现ChMC(机箱管理控制器)的主要功能包括:
1)各个功能模块的上下电管理;
2)机箱内部温度以及模块信息检测(包括模块类型及模块在线信息监测,CPU模块的硬盘及内存等信息);
3)响应远程控制命令,处理错误警告并记录系统日志;
4)对外通过网络提供机箱及各模块统一的管理接口。
单元管理子模块由机箱管理软件ChMC、数据处理模块、系统CPU模块上的Agent等组成。
4. 软件组成
单元管理子模块软件对整个单元软硬件资源进行可视化的管理和调度。在统一的资源管理模式下,对下更好地管理硬件资源,向上支撑应用的高效、自动化管理。单元管理子模块软件集中管理和展现的资源包括:
(1)系统信息:系统配置、网络拓扑、运行状态、故障、告警等
(2)核心硬件信息:CPU模块、接口模块、电源模块的信息,信息由各模块上的IPMC上报。
本软件采用分层架构和监控管理代理方式,并提供一个基于B/S架构的统一Web监控管理门户实现从处理器到业务应用全覆盖式监控与管理,具有监控信息采集与处理、实时状态展示、网络拓扑呈现、事件告警、高可用集群管理、安全管控、资源管理与任务调度、日志操作等功能,为整个单元高效安全可靠运行和便捷管理提供有力工具。
基础支持软件用于实现ChMC初始化、引导、接口驱动及管理等功能,提供标准接口,支持上层软件模块的开发。标准库提供ChMC部分的人机接口、内存分配与回收、线程管理等标准功能,对动态库进行裁剪以适应体积要求。
5. 从IPMI模块设计
作为机箱管理系统的重要组成部分,模块管理子模块承担机箱内多个不同类型功能模块的IPMI管理控制任务。为单元管理提供访问本地FRU的管理接口。板卡管理子系统主要实现下列管理功能:
1)实现功能板卡的插入检测、通断电、自检、冷热启动等相关控制;
2)响应主控板卡通过IPMB总线发送的命令及错误处理;
3)实现温度、电压传感器的实时监测;
4)实现机箱管理访问控制FRU和SDR信息;
5)向机箱管理软件上报各类信息,包括负载电源自检、现场可替换单元状态切换、各类传感器告警事件的实时上报。
单元管理子模块通过IPMB总线向功能板卡发送IPMI管理命令,IPMC控制器内的命令解析模块实现收发消息包的解析组包功能。命令处理模块根据IPMI协议标准将解析后的数据进行处理。
6. 名词解释
BMC:IPMI管理平台的核心控制器
IPMB:IPMB是用于BMC与外围组织管理控制器(SMC)的通信,这些外围组织管理器一般控制特定设备,其上传递的是IPMI命令,IPMB是基于I2C的总线。
ICMB: 在IPMB总线上,连接着一个ICMB桥,通过ICMB可以和远程的另一个管理平台通信
SDR: (Sensor Data Record) 用于保存传感器的具体配置信息,如告警门限、事件触发是否允许等配置数据
SEL: (Sensor Event Log) 用于保存传感器产生的告警事件等数据
SMBus: BMC通过芯片上一对SMBus接口连接网络。
6. 代码
下面是以stm32f2的I2C1(IPMB)为例的初始化代码:
void I2C1_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// SCL PB6
// SDA PB7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//I2C必须开漏输出,实现线与逻辑
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);
}
void I2C1_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0xA0; //从机地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE); //使能中断
I2C_Cmd(I2C1, ENABLE); //使能I2C
}
void I2C1_Init(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
I2C1_GPIO_Configuration();
I2C1_Configuration();
}
void I2C1_EV_IRQHandler(void)
{
__IO uint32_t SR1Register =0;
__IO uint32_t SR2Register =0;
SR1Register = I2C1->SR1;
SR2Register = I2C1->SR2;
// printf("I2C1_EV_IRQHandler\r\n");
/* I2C1是从机(MSL = 0) */
if((SR2Register &0x0001) != 0x0001)
{
/* 主机已发生地址(ADDR = 1: EV1) */
if((SR1Register & 0x0002) == 0x0002)
{
/* 清除标志,准备接收数据 */
SR1Register = 0;
SR2Register = 0;
Rx_Idx_IIC1=0;
Tx_Idx_IIC1=0;
}
/* 接收数据(RXNE = 1: EV2) */
if((SR1Register & 0x0040) == 0x0040)
{
Buffer_Rx_IIC1[Rx_Idx_IIC1++] = I2C1->DR;
SR1Register = 0;
SR2Register = 0;
}
/* 检测到停止条件(STOPF =1: EV4) */
if(( SR1Register & 0x0010) == 0x0010)
{
I2C1->CR1 |= 0x0001;
SR1Register = 0;
SR2Register = 0;
Flag_RcvOK_IIC1 = 1;
}
/* 发送数据(TxE = 1: EV3) */
if((SR1Register & 0x0080) == 0x0080)
{
I2C1->DR = Response_Message[Tx_Idx_IIC1++];
SR1Register = 0;
SR2Register = 0;
}
/* 检测到非应答(AF =1: EV3-2) */
if(( SR1Register & 0x0400) == 0x0400)
{
I2C1->SR1 &= 0xFDFF;
SR1Register = 0;
SR2Register = 0;
printf("read\r\n");
}
}
}
void I2C1_ER_IRQHandler(void) {
__IO uint32_t SR1Register =0;
__IO uint32_t SR2Register =0;
SR1Register = I2C1->SR1;
SR2Register = I2C1->SR2;
printf("I2C1_ER_IRQHandler\r\n");
if(I2C_GetITStatus(I2C1, I2C_IT_SMBALERT)) {
printf("I2C_IT_SMBALERT\r\n");
I2C_ClearITPendingBit(I2C1, I2C_IT_SMBALERT);
}
else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) {
printf("I2C_IT_TIMEOUT\r\n");
I2C_ClearITPendingBit(I2C1, I2C_IT_TIMEOUT);
}
else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR)) {
printf("I2C_IT_PECERR\r\n");
I2C_ClearITPendingBit(I2C1, I2C_IT_PECERR);
}
else if(I2C_GetITStatus(I2C1, I2C_IT_OVR)) {
printf("I2C_IT_OVR\r\n");
I2C_ClearITPendingBit(I2C1, I2C_IT_OVR);
}
else if(I2C_GetITStatus(I2C1, I2C_IT_AF)) {
printf("I2C_IT_AF\r\n");
I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
}
else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO)) {
printf("I2C_IT_ARLO\r\n");
I2C_ClearITPendingBit(I2C1, I2C_IT_ARLO);
}
else if(I2C_GetITStatus(I2C1, I2C_IT_BERR)) {
printf("I2C1_IT_BERR\r\n");
I2C_ClearITPendingBit(I2C1, I2C_IT_BERR);
}
I2C1->CR1 |= 0x0001;
SR1Register = 0;
SR2Register = 0;
}