open ipmi内核实现简介(使用串口)

智能平台管理接口 (IPMI) 是一种开放标准的硬件管理接口规格,定义了嵌入式管理子系统进行通信的特定方法。IPMI 信息通过基板管理控制器 (BMC)(位于 IPMI 规格的硬件组件上)进行交流。使用低级硬件智能管理而不使用操作系统进行管理,具有两个主要优点: 首先,此配置允许进行带外服务器管理;其次,操作系统不必负担传输系统状态数据的任务。
ipmi在linux下的实现由几个模块组成:ipmi_msghandler,ipmi_devintf,ipmi_serial,ipmi_serial_codec*这几个模块分别负责不同的功能,它们互相协作完成ipmi的功能。其中ipmi serial被移除了linux内核,原因在linux的文档中关于ipmi serial串口驱动中有所描述。但是在社区中仍有对它的支持。

一、ipmi_msghandler

该模块是ipmi消息处理的核心,它不依赖于其它模块,但是它也需要调用其它模块的接口。为了实现这一点,它了解所有的IPMI的核心数据结构,它所需要调用的其它模块的函数接口都通过数据结构中的指针来实现。因此可以这么说,该模块对外提供了接口,当其它模块需要该模块提供服务时就直接调用其提供的接口,而当该模块需要其他模块的服务时,就通过相应数据结构中的指针来实现。该模块维护了一个链表ipmi_interfaces,它包括了所有的ipmi接口。IPMI所涉及到的核心数据结构的关系如图:


1.初始化/卸载

该模块的初始化相对比较简单,主要完成了
  • 注册驱动
  • 创建proc文件
  • 启动定时器ipmi_timer
  • 注册到panic_block上
该模块的卸载也相对比较简单,就是初始化的逆过程

2.定时器处理

该模块包括了一个定时器,它的处理函数中会重新启动自己,因此它是一个定时到期的定时器。它完成的功能包括:
  • 每超时IPMI_REQUEST_EV_TIME次就调用一次ipmi_request_event,该函数最终会为每一个不工作在maintenance模式的并且在ipmi_interfaces链表中的接口调用一次它的request_events。
  • 调用ipmi_timeout_handler,该函数会遍历所有的在ipmi_interfaces链表的接口,并且:
    • 对在接口的waiting_msgs链表中的消息调用handle_new_recv_msg处理消息
    • 对在接口的seq_table中的消息进行检查处理
    • 进行maintenance模式的处理

3.与上层以及下层的接口

该模块是ipmi消息处理的核心,它与上层,即直接用用户空间交互的模块已经下层即和真正的驱动交互的模块都有接口。
  • 与上层的接口:该模块提供了ipmi_create_user来让上层创建一个user,同时要求上层提供与该user相关的struct ipmi_user_hndl,当本模块需要向该user提交信息时,就通过该结构中的指针来完成。
  • 和下层的接口:该模块提供了ipmi_register_smi来让下层注册一个smi,同时要求注册者提供一个与该接口相关的struct ipmi_smi_handlers,当该模块需要使用下层服务时,就会使用该结构中的指针。该模块提供给下层的接口主要是ipmi_smi_msg_received
另外通过EXPORT_SYMBOL即可找到该模块对外提供的所有接口。

4.发送消息/接收消息

1).发送消息

当上层发送消息时,它们需要使用该模块提供的接口:
  • ipmi_request_settime
  • ipmi_request_supply_msgs
  • ipmi_request_with_source
来完成,这几个函数最终会调到接口的handlers->sender来把消息交给下层。

2).接收消息

当下层收到消息时,会调用ipmi_smi_msg_received来将消息提交给本模块。该函数会把消息添加到接口的waiting_msgs链表中,或者直接调用handle_new_recv_msg进行处理。handle_new_recv_msg会找到user并把消息通过与user关联的struct ipmi_user_hndl提交给用户。
需要注意的是,默认情况下只有消息会被提交给user,如果user想要接收命令,事件,就需要通过该模块提供的接口ipmi_register_for_cmd以及ipmi_set_gets_events来告诉本模块它关心这些信息。当它们不想继续接收命令,事件时就需要 通过ipmi_unregister_for_cmd以及ipmi_set_gets_events来解除这种关心。

本模块与其它模块在消息收发上的接口如图:


二、ipmi_devint

该模块用于向用户空间提供IPMI的接口。是内核和用户空间的接口。该模块依赖于模块ipmi_msghandler。

1.初始化/卸载

在模块初始化时会注册一个名字为ipmidev的字符设备,并绑定相应的文件操作ipmi_fops。同时会通过ipmi_smi_watcher_register为所有在链表ipmi_interfaces中的接口创建设备文件,创建的设备文件名为ipmi%d,其中%d为接口的编号。
卸载时会先删除所有设备文件,然后卸载字符设备ipmidev

2.和内核通信

如果想要和内核中的ipmi通信,首先需要打开一个设备文件ipmi%d。在打开设备文件时,本模块会调用ipmi_create_user创建一个user,同时向ipmi_msghandler提供一个该user接收信息的回调函数,当ipmi_msghandler向该user提交信息时会用到该回调函数。
在打开一个设备文件后,即可使用ioctl和内核通信。

3.向外提供的接口

通过文件操作提供给用户空间的接口
通过struct ipmi_user_hndl向ipmi_msghandler提供的接收消息的窗口

4.需要外部提供的接口

和接口设备文件相关的接口:
  • ipmi_smi_watcher_register
  • ipmi_smi_watcher_unregister
和user的创建和删除相关的接口:
  • ipmi_create_user
  • ipmi_destroy_user
ioctl命令相关:
  • ipmi_validate_addr验证地址
  • ipmi_addr_length获得地址长度
  • ipmi_request_settime发送requset
  • ipmi_free_recv_msg释放消息
  • ipmi_register_for_cmd注册命令,即声明自己关心这个命令
  • ipmi_unregister_for_cmd
  • ipmi_set_gets_events设置获取事件标记,并获取事件。甚至了标记则表明本user关心事件
  • ipmi_set_my_address
  • ipmi_get_my_address
  • ipmi_set_my_LUN
  • ipmi_get_my_LUN
  • ipmi_set_maintenance_mode
  • ipmi_get_maintenance_mode

5.发送/接收信息

接收信息:默认情况下,只有消息会被发送给user。这是通过和user关联的ipmi_msghandler实现的,ipmi_msghandler会调用ipmi_msghandler中的file_receive_handler,该接口的会把消息放入一个user私有的接收消息列表中。当用户发送接收消息的ioctl时,就会从该消息列表取出消息。
发送信息:用户空间发送的requset通过ioctl命令到达内核后,最终通过ipmi_request_settime发送出去。

本模块在收发消息上与其它模块的接口如图所示:


三、ipmi_serial

ipmi_serial模块是ipmi的串口驱动,用于支持使用串口和bmc通信。该模块是串口驱动的核心,当前串口驱动可以工作在三种模式,deriect,radysis_ascii,terminal。每种模式以一种ipmi_serial_codec表示。

该模块维护了两个链表,codec_list和info_list,前一种包括了当前系统中注册的模式,后一个列表包括了当前系统中所配置的ipmiserial接口。

1.初始化/卸载

初始化的动作:根据模块参数尝试调用ipmi_serial_setup_one以创建一个ipmi serial interface。在ipmi_serial_setup_one中,会:
  • 创建新的struct ipmi_serial_info结构
  • 设置ipmi_serial_info中的定时器,该定时器会在调用ipmi_register_smi时被启动
  • 解析参数并初始化infor结构
  • 如果是一个新的接口,就会被加入到info_list链表中,否则做清理工作后返回
  • 如果是一个新的接口,还会检查所指定的模式是否已经加载(即是否已存在于codec_list中),如果已经存在,则会尝试调用setup_intf创建一个接口。
setup_intf会完成最终的创建工作(部分工作是ipmi_serial_found完成的):
  • 找到实际的物理接口,即实际的serial接口,并将相关的信息传递给该serial接口,info->port->state->direct = &info->direct; 这一步很关键,serial驱动将使用这里的信息来完成信息的传递,即信息由serial驱动向ipmi serial接口的传递。
  • 调用串口的ops->startup
  • 设置serial的相关配置信息
  • 调用codec注册的init函数
  • 如果codec有注册start函数,则调用info->codec->init和info->codec->start来尝试向BMC发送一个请求,并等待响应,收到响应则表示可以工作,否则就表示不能工作;如果没有注册start函数,则认为是可以工作的。
  • 调用ipmi_register_smi注册接口到ipmi_msghandler,并提供相应的struct ipmi_smi_handlers给ipmi_msghandler使用
  • 创建相应的proc文件
卸载的工作:模块卸载时做的事情很简单,就是注册的逆过程。的ipmi_serial_cleanup_one会完成实际的接口清理工作。在命令的处理中,以及在codec的unregister中也有调用该函数。

2.定时器

每个ipmi_serial_info都包括了一个定时器,它的处理函数中会重新启动自己,因此它是一个定时到期的定时器。它完成的功能包括:
  • 增加timer_ticks计数
  • 调用timeout_handling,该函数在做了一些处理后,最终会调用start_next_msg,这是本模块的核心处理函数,无论是发送还是接收,最终都由它处理。

3.和外部的接口

本模块除了和上层(ipmi_msghandler)以及下层(所支持的codec)有接口外,还通过配置文件和用户空间有一个关键接口。

1).和用户空间的关键接口:

/sys/module/ipmi_serial/parameters/hotmod
可以通过如下命令来添加一个接口:
echo add,ttyS3,38400N81r,RadisysAscii > hotmod
该命令的处理函数为hotmod_handler,它会调用ipmi_serial_setup_one或ipmi_serial_remove_one(进一步的ipmi_serial_cleanup_one)

2).和上层的接口

该模块和上层即 ipmi_msghandler的接口分为两部分:
  • 本模块提供给ipmi_msghandler的通过struct ipmi_smi_handlers提供给它
  • 本模块需要的上层接口主要包括:
    • ipmi_register_smi
    • ipmi_smi_msg_received

3).本模块和下层的接口

本模块和下层(所支持的codec)的接口也分为两部分:
  • 本模块提供给下层的接口通过EXPORT_SYMBOL即可找到
  • 下层模块提供给本模块的接口包含在struct ipmi_serial_codec中,并通过ipmi_serial_codec_register提供给本模块

4.发送消息/接收消息

1).发送消息

当上层发送消息时,它使用struct ipmi_smi_handlers中的sender(即ipmi_serial_sender)来将消息交给本模块。
这个函数通过最终会通过start_next_msg调到info->codec->send_msg将信息提交给下层。之后,该消息在被codec模块处理后又会被提交给本模块的ipmi_serial_ll_xmit,最终通过uart_direct_write发送出去

2).接收消息

当下层收到消息时,会调用ipmi_serial_ll_recv来将消息提交给本模块。这个函数最终会通过start_next_msg调到ipmi_smi_msg_received将消息提交给上层。
而serial驱动的信息则是通过info->direct中的指针进入ipmi serial的,实际上即进入到了info->codec->handle_char中。相关的代码:
ipmi_serial_setup_one:
info->direct.direct_data = info;
      info->direct.handle_char = ipmi_serial_handle_char;
      info->direct.push = ipmi_serial_push;
     setup_intf:
            info->port->state->direct = &info->direct;
ipmi_serial_push:
        info->codec->handle_char

本模块和其它模块在消息收发上的接口如图:


四、ipmi_serial_codec

IPMI serial支持几种codec模式,这几种模式可以理解为编解码器,发送时进行编码接收时进行解码,对于每种模式来说,它只需要将其注册到ipmi_serial并提供相应的编解码功能所需的函数指针即可。

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值