Linux IPMI 驱动¶
- 作者:
Corey Minyard <minyard@mvista.com> / <minyard@acm.org>
智能平台管理接口(IPMI)是一种用于控制监控系统的智能设备的标准。它提供系统中传感器的动态发现功能,并能监控传感器并在其值改变或超出特定范围时通知用户。它还为现场可更换单元(FRU)和看门狗定时器提供了标准化的数据库。
要使用此功能,您的系统需要一个到 IPMI 控制器(称为基板管理控制器,或 BMC)的接口,以及能够使用 IPMI 系统的管理软件。
本文档描述了如何使用 Linux 的 IPMI 驱动。如果您不熟悉 IPMI 本身,请访问网站 https://www.intel.com/design/servers/ipmi/index.htm。IPMI 是一个很大的主题,我无法在此处全部涵盖!
配置¶
Linux IPMI 驱动是模块化的,这意味着您必须根据您的硬件选择几项才能使其正常工作。其中大部分可在“字符设备”菜单下的 IPMI 菜单中找到。
无论如何,您必须选择“IPMI 顶层消息处理程序”才能使用 IPMI。除此之外,您如何操作取决于您的需求和硬件。
消息处理程序不提供任何用户级接口。内核代码(如看门狗)仍可使用它。如果您需要从用户空间访问,并且希望通过设备驱动访问,则需要选择“IPMI 的设备接口”。
驱动接口取决于您的硬件。如果您的系统正确提供了 IPMI 的 SMBIOS 信息,驱动将检测到它并直接工作。如果您的主板带有标准接口(通常是“KCS”、“SMIC”或“BT”,请查阅您的硬件手册),请选择“IPMI SI 处理程序”选项。此外,还存在一个直接 I2C 访问 IPMI 管理控制器的驱动。有些主板支持此功能,但尚不确定它是否适用于所有主板。为此,请选择“IPMI SMBus 处理程序”,但如果 SMBIOS/ACPI 信息不正确或不存在,您可能需要进行一些调试才能确定它是否适用于您的系统。同时启用这些功能并让驱动自动检测存在的接口是相当安全的。
您通常应在系统上启用 ACPI,因为带有 IPMI 的系统可能包含描述它们的 ACPI 表。
如果您有一个标准接口,并且主板制造商已正确完成其工作,则 IPMI 控制器应自动检测(通过 ACPI 或 SMBIOS 表)并正常工作。遗憾的是,许多主板没有此信息。驱动会尝试使用标准默认值,但可能无法工作。如果您遇到这种情况,您需要阅读下面名为“SI 驱动”或“SMBus 驱动”的部分,了解如何手动配置您的系统。
IPMI 定义了一个标准看门狗定时器。您可以通过“IPMI 看门狗定时器”配置选项启用它。如果您将驱动编译到内核中,则可以通过内核命令行选项使看门狗定时器在初始化后立即启动。它还有许多其他选项,请参阅下面的“看门狗”部分了解更多详细信息。请注意,如果看门狗被关闭,它也可以继续运行(默认情况下在关闭时禁用)。进入“看门狗卡”菜单,启用“看门狗定时器支持”,并启用选项“关闭时禁用看门狗关机”。
IPMI 系统通常可以使用 IPMI 命令关闭。选择“IPMI 关机”即可实现此功能。驱动将自动检测系统是否可以通过 IPMI 关闭。即使您的系统不支持此选项,启用它也是安全的。这适用于 ATCA 系统、Radisys CPI1 卡以及任何支持标准机箱管理命令的 IPMI 系统。
如果您希望驱动在发生 panic 时将事件写入事件日志,请启用“在 panic 时向所有 BMC 生成 panic 事件”选项。如果您希望将整个 panic 字符串使用 OEM 事件写入事件日志,请启用“生成包含 panic 字符串的 OEM 事件”选项。您还可以通过将 ipmi_msghandler 模块中名为“panic_op”的模块参数设置为“event”或“string”来动态启用这些功能。将该参数设置为“none”将禁用此功能。
基本设计¶
Linux IPMI 驱动被设计为高度模块化和灵活,您只需选择您需要的部分,即可通过多种不同方式使用它。因此,它被分解为许多代码块。这些块(按模块名称)是:
ipmi_msghandler - 这是 IPMI 系统的核心软件。它处理所有消息、消息计时和响应。IPMI 用户连接到此处,IPMI 物理接口(称为系统管理接口,或 SMI)也连接到此处。这提供了 IPMI 的内核接口,但不提供供应用程序进程使用的接口。
ipmi_devintf - 这为 IPMI 驱动提供了一个用户空间 IOCTL 接口,此设备的每个打开文件都作为 IPMI 用户连接到消息处理程序。
ipmi_si - 用于各种系统接口的驱动。它支持 KCS、SMIC 和 BT 接口。除非您有 SMBus 接口或您自己的自定义接口,否则您可能需要使用它。
ipmi_ssif - 用于访问 SMBus 上 BMC 的驱动。它使用 I2C 内核驱动的 SMBus 接口通过 SMBus 发送和接收 IPMI 消息。
ipmi_powernv - 用于访问 POWERNV 系统上 BMC 的驱动。
ipmi_watchdog - IPMI 要求系统具有功能强大的看门狗定时器。此驱动在 IPMI 消息处理程序之上实现了标准 Linux 看门狗定时器接口。
ipmi_poweroff - 某些系统支持通过 IPMI 命令关闭的能力。
bt-bmc - 这不是主驱动的一部分,而是用于访问 BT 接口的 BMC 侧接口的驱动。它用于运行 Linux 的 BMC,以向主机提供接口。
这些都可以通过配置选项单独选择。
大部分接口文档都在头文件中。IPMI 头文件是:
linux/ipmi.h - 包含 IPMI 的用户接口和 IOCTL 接口。
linux/ipmi_smi.h - 包含系统管理接口(与 IPMI 控制器接口的实体)使用的接口。
linux/ipmi_msgdefs.h - 基本 IPMI 消息的通用定义。
寻址¶
IPMI 寻址的工作方式很像 IP 地址,您有一个覆盖层来处理不同的地址类型。覆盖层是:
struct ipmi_addr
{
int addr_type;
short channel;
char data[IPMI_MAX_ADDR_SIZE];
};
addr_type 决定了地址的实际类型。驱动当前理解两种不同类型的地址。
“系统接口”地址定义为:
struct ipmi_system_interface_addr
{
int addr_type;
short channel;
};
类型为 IPMI_SYSTEM_INTERFACE_ADDR_TYPE。这用于直接与当前卡上的 BMC 通信。通道必须是 IPMI_BMC_CHANNEL。
要通过 BMC 在 IPMB 总线上发送的消息使用 IPMI_IPMB_ADDR_TYPE 地址类型。格式为:
struct ipmi_ipmb_addr
{
int addr_type;
short channel;
unsigned char slave_addr;
unsigned char lun;
};
这里的“channel”通常为零,但有些设备支持多个通道,它对应于 IPMI 规范中定义的通道。
对于发送方直接位于 IPMB 总线上且无需通过 BMC 的情况,还存在一个 IPMB 直接地址。您可以使用 IPMI_IPMB_DIRECT_ADDR_TYPE 和以下格式向 IPMB 上的特定管理控制器 (MC) 发送消息:
struct ipmi_ipmb_direct_addr
{
int addr_type;
short channel;
unsigned char slave_addr;
unsigned char rq_lun;
unsigned char rs_lun;
};
通道始终为零。您还可以从已注册处理和响应的其他 MC 接收命令,因此您可以使用此功能在总线上实现管理控制器。
消息¶
消息定义为:
struct ipmi_msg
{
unsigned char netfn;
unsigned char lun;
unsigned char cmd;
unsigned char *data;
int data_len;
};
驱动负责添加/剥离头部信息。数据部分只是要发送的数据(不要在此处放置寻址信息)或响应。请注意,响应的完成代码是“数据”中的第一个项目,它不会被剥离,因为所有消息在规范中都是这样定义的(因此使偏移量计算更容易 :-)。
当从用户空间使用 IOCTL 接口时,您必须为“data”提供一个数据块,填充它,并将 data_len 设置为数据块的长度,即使在接收消息时也是如此。否则,驱动将没有地方放置消息。
从内核的消息处理程序上传的消息将以以下形式传入:
struct ipmi_recv_msg
{
struct list_head link;
/* The type of message as defined in the "Receive Types"
defines above. */
int recv_type;
ipmi_user_t *user;
struct ipmi_addr addr;
long msgid;
struct ipmi_msg msg;
/* Call this when done with the message. It will presumably free
the message and do any other necessary cleanup. */
void (*done)(struct ipmi_recv_msg *msg);
/* Place-holder for the data, don't make any assumptions about
the size or existence of this, since it may change. */
unsigned char msg_data[IPMI_MAX_MSG_LENGTH];
};
您应该查看接收类型并适当地处理消息。
上层接口(消息处理程序)¶
接口的上层为用户提供了 IPMI 接口的一致视图。它允许寻址多个 SMI 接口(因为有些主板上确实有多个 BMC),用户无需关心其下是哪种类型的 SMI。
监听接口¶
当您的代码启动时,IPMI 驱动可能已检测到 IPMI 设备,也可能未检测到。因此,您可能需要延迟设置直到设备被检测到,或者您可以立即进行设置。为了处理这种情况并允许发现,您可以使用 ipmi_smi_watcher_register() 注册一个 SMI 观察器,以迭代接口并告知您它们的出现和消失。
创建用户¶
要使用消息处理程序,您必须首先使用 ipmi_create_user 创建一个用户。接口编号指定您要连接的 SMI,并且您必须提供回调函数,以便在数据传入时调用。这还允许您传入一段数据,即 handler_data,它将在所有调用中返回给您。
完成后,调用 ipmi_destroy_user() 以销毁用户。
从用户空间,打开设备会自动创建一个用户,关闭设备会自动销毁用户。
消息传递¶
要从内核发送消息,ipmi_request_settime() 调用几乎完成了所有消息处理。大多数参数都是不言自明的。但是,它需要一个“msgid”参数。这不是消息的序列号。它只是一个长值,当消息的响应返回时会传回。您可以随意使用它。
响应将通过您在 ipmi_create_user() 中传递的“handler”的 ipmi_recv_hndl 字段指向的函数返回。请记住也要查看接收类型。
从用户空间,您需要填写一个 ipmi_req_t 结构体并使用 IPMICTL_SEND_COMMAND ioctl。对于传入的数据,您可以使用 select() 或 poll() 等待消息传入。但是,您不能使用 read() 获取它们,您必须调用 IPMICTL_RECEIVE_MSG 并使用 ipmi_recv_t 结构体才能实际获取消息。请记住,您必须在 msg.data 字段中提供指向数据块的指针,并且必须使用数据大小填充 msg.data_len 字段。这为接收方提供了一个实际放置消息的位置。
如果消息无法放入您提供的数据中,您将收到 EMSGSIZE 错误,并且驱动将把数据留在接收队列中。如果您想获取它并截断消息,请使用 IPMICTL_RECEIVE_MSG_TRUNC ioctl。
当您在 IPMB 总线上发送命令(由 IPMI 规范中的 netfn 最低位定义)时,驱动将自动为命令分配序列号并保存命令。如果在 IPMI 指定的 5 秒内未收到响应,它将自动生成一个响应,表明命令超时。如果收到一个未经请求的响应(例如,如果是在 5 秒之后),该响应将被忽略。
在内核中,收到消息并处理完毕后,您必须对其调用 ipmi_free_recv_msg(),否则会造成消息泄露。请注意,您绝不应更改消息的“done”字段,这是正确清理消息所必需的。
请注意,在发送时,有一个 ipmi_request_supply_msgs() 调用,允许您提供 SMI 和接收消息。这对于即使系统缓冲区耗尽也能工作的代码片段非常有用(例如,看门狗定时器就使用了它)。您提供自己的缓冲区和自己的释放例程。不过,由于管理自己的缓冲区很棘手,因此不建议在正常情况下使用。
事件和传入命令¶
驱动负责轮询 IPMI 事件和接收命令(命令不是响应,它们是 IPMB 总线上其他设备发送给您的命令)。要接收这些事件和命令,您必须注册它们,它们不会自动发送给您。
要接收事件,您必须调用 ipmi_set_gets_events() 并将“val”设置为非零。驱动自启动以来收到的任何事件都将立即传递给第一个注册事件的用户。之后,如果有多个用户注册了事件,他们都将收到所有传入的事件。
为了接收命令,您必须单独注册您要接收的命令。调用 ipmi_register_for_cmd() 并为每个要接收的命令提供 netfn 和命令名称。您还可以指定一个通道的位掩码,您希望从中接收命令(如果您不关心,则使用 IPMI_CHAN_ALL 接收所有通道)。每个 netfn/cmd/channel 只能注册一个用户,但不同的用户可以注册不同的命令,或者如果通道位掩码不重叠,则可以注册相同的命令。
要响应收到的命令,请在返回的 netfn 中设置响应位,使用从收到的消息中获取的地址,并使用与您在收到的消息中获得的相同的 msgid。
从用户空间,提供了等效的 IOCTL 来执行这些功能。
下层(SMI)接口¶
如前所述,多个 SMI 接口可以注册到消息处理程序,每个接口在注册时都会被分配一个接口编号。它们通常按照注册顺序分配,但是如果一个 SMI 注销后另一个 SMI 注册,则所有保证都失效。
ipmi_smi.h 定义了管理接口的接口,请参阅该文件了解更多详细信息。
SI 驱动¶
SI 驱动允许在系统中配置 KCS、BT 和 SMIC 接口。它通过多种不同的方法发现接口,具体取决于系统。
您可以在模块加载命令行上指定多达四个接口并控制一些模块参数
modprobe ipmi_si.o type=<type1>,<type2>....
ports=<port1>,<port2>... addrs=<addr1>,<addr2>...
irqs=<irq1>,<irq2>...
regspacings=<sp1>,<sp2>,... regsizes=<size1>,<size2>,...
regshifts=<shift1>,<shift2>,...
slave_addrs=<addr1>,<addr2>,...
force_kipmid=<enable1>,<enable2>,...
kipmid_max_busy_us=<ustime1>,<ustime2>,...
unload_when_empty=[0|1]
trydmi=[0|1] tryacpi=[0|1]
tryplatform=[0|1] trypci=[0|1]
除 try... 项外,这些都是列表,第一项用于第一个接口,第二项用于第二个接口,依此类推。
si_type 可以是“kcs”、“smic”或“bt”。如果留空,则默认为“kcs”。
如果您为某个接口指定非零的 addrs,则驱动将使用给定内存地址作为设备的地址。这将覆盖 si_ports。
如果您为某个接口指定非零的 ports,则驱动将使用给定的 I/O 端口作为设备地址。
如果您为某个接口指定非零的 irqs,则驱动将尝试使用给定中断用于设备。
其他的 try... 项通过其对应的名称禁用发现。这些默认都已启用,将其设置为零即可禁用。tryplatform 禁用 openfirmware。
接下来的三个参数与寄存器布局有关。接口使用的寄存器可能不会出现在连续位置,并且它们可能不在 8 位寄存器中。这些参数允许更精确地指定寄存器中数据的布局。
regspacings 参数给出连续寄存器起始地址之间的字节数。例如,如果 regspacing 设置为 4 且起始地址为 0xca2,则第二个寄存器的地址将为 0xca6。这默认为 1。
regsizes 参数给出寄存器的大小(以字节为单位)。IPMI 使用的数据是 8 位宽的,但它可能位于更大的寄存器中。此参数允许指定读写类型。它可以是 1、2、4 或 8。默认值为 1。
由于寄存器大小可能大于 32 位,IPMI 数据可能不在低 8 位中。regshifts 参数给出移位数据以获取实际 IPMI 数据的量。
slave_addrs 指定本地 BMC 的 IPMI 地址。这通常是 0x20,驱动默认为此,但如果不是,则可以在驱动启动时指定。
force_ipmid 参数强制启用(如果设置为 1)或禁用(如果设置为 0)内核 IPMI 守护进程。通常这由驱动自动检测,但中断损坏的系统可能需要启用,或者不希望守护进程(不需要性能,不希望 CPU 占用)的用户可以禁用它。
如果 unload_when_empty 设置为 1,则如果驱动未找到任何接口或所有接口都无法工作,则驱动将被卸载。默认值为 1。设置为 0 在热插拔时有用,但显然仅适用于模块。
当编译到内核中时,参数可以在内核命令行中指定为:
ipmi_si.type=<type1>,<type2>...
ipmi_si.ports=<port1>,<port2>... ipmi_si.addrs=<addr1>,<addr2>...
ipmi_si.irqs=<irq1>,<irq2>...
ipmi_si.regspacings=<sp1>,<sp2>,...
ipmi_si.regsizes=<size1>,<size2>,...
ipmi_si.regshifts=<shift1>,<shift2>,...
ipmi_si.slave_addrs=<addr1>,<addr2>,...
ipmi_si.force_kipmid=<enable1>,<enable2>,...
ipmi_si.kipmid_max_busy_us=<ustime1>,<ustime2>,...
它的工作方式与同名的模块参数相同。
如果您的 IPMI 接口不支持中断且是 KCS 或 SMIC 接口,IPMI 驱动将为该接口启动一个内核线程以帮助加速。这是一个低优先级的内核线程,在 IPMI 操作进行时不断轮询 IPMI 驱动。force_kipmid 模块参数将允许用户强制开启或关闭此线程。如果您强制关闭它并且没有中断,驱动将运行得非常缓慢。不要怪我,这些接口太糟糕了。
不幸的是,这个线程可能会根据接口的性能占用大量 CPU。这会浪费大量 CPU 并导致检测空闲 CPU 和增加功耗等各种问题。为了避免这种情况,kipmid_max_busy_us 设置了 kipmid 在休眠一个滴答之前旋转的最大时间(以微秒为单位)。此值在性能和 CPU 浪费之间设置了一个平衡,需要根据您的需求进行调整。也许有一天会添加自动调整,但这不是一件简单的事情,即使是自动调整也需要根据用户所需的性能进行调整。
驱动支持接口的热插拔。这样,接口可以在内核启动并运行后添加或移除。这是通过 /sys/modules/ipmi_si/parameters/hotmod 完成的,它是一个只写参数。您向此接口写入一个字符串。字符串的格式为:
<op1>[:op2[:op3...]]
“op”是:
add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
您可以在一行上指定多个接口。“opt”是:
rsp=<regspacing>
rsi=<regsize>
rsh=<regshift>
irq=<irq>
ipmb=<ipmb slave addr>
它们的含义与上面讨论的相同。请注意,您也可以在内核命令行中使用此功能,以便以更紧凑的格式指定接口。请注意,在移除接口时,仅使用前三个参数(SI 类型、地址类型和地址)进行比较。移除时,任何选项都将被忽略。
SMBus 驱动 (SSIF)¶
SMBus 驱动允许在系统中配置多达 4 个 SMBus 设备。默认情况下,驱动只会注册它在 DMI 或 ACPI 表中找到的设备。您可以在模块加载时(对于模块)通过以下方式更改此设置:
modprobe ipmi_ssif.o
addr=<i2caddr1>[,<i2caddr2>[,...]]
adapter=<adapter1>[,<adapter2>[...]]
dbg=<flags1>,<flags2>...
slave_addrs=<addr1>,<addr2>,...
tryacpi=[0|1] trydmi=[0|1]
[dbg_probe=1]
alerts_broken
地址是正常的 I2C 地址。adapter 是适配器的字符串名称,如 /sys/bus/i2c/devices/i2c-<n>/name 中所示。它不是 i2c-<n> 本身。此外,比较时会忽略空格,所以如果名称是“This is an I2C chip”,您可以说 adapter_name=ThisisanI2cchip。这是因为在内核参数中传递空格很困难。
调试标志是为每个找到的 BMC 设置的位标志,它们是:IPMI 消息: 1,驱动状态: 2,计时: 4,I2C 探测: 8
tryxxx 参数可用于禁用从各种来源检测接口。
将 dbg_probe 设置为 1 将启用 SMBus 上 BMC 探测和检测过程的调试。
slave_addrs 指定本地 BMC 的 IPMI 地址。这通常是 0x20,驱动默认为此,但如果不是,则可以在驱动启动时指定。
alerts_broken 不启用 SSIF 的 SMBus 警报。否则,SMBus 警报将在支持的硬件上启用。
在 SMBus 上发现符合 IPMI 标准的 BMC 可能会导致 I2C 总线上的设备失效。SMBus 驱动会以块写入的方式将“获取设备 ID”IPMI 消息写入 I2C 总线,并等待响应。此操作可能对某些 I2C 设备有害。强烈建议您将已知的 I2C 地址提供给 smb_addr 参数中的 SMBus 驱动,除非您有 DMI 或 ACPI 数据来告知驱动使用哪个地址。
当编译到内核中时,地址可以在内核命令行中指定为:
ipmb_ssif.addr=<i2caddr1>[,<i2caddr2>[...]]
ipmi_ssif.adapter=<adapter1>[,<adapter2>[...]]
ipmi_ssif.dbg=<flags1>[,<flags2>[...]]
ipmi_ssif.dbg_probe=1
ipmi_ssif.slave_addrs=<addr1>[,<addr2>[...]]
ipmi_ssif.tryacpi=[0|1] ipmi_ssif.trydmi=[0|1]
这些选项与模块命令行上的选项相同。
I2C 驱动不支持非阻塞访问或轮询,因此此驱动无法执行 IPMI panic 事件、在 panic 时扩展看门狗或其他与 panic 相关的 IPMI 功能,除非进行特殊的内核补丁和驱动修改。您可以在 openipmi 网页上获取这些功能。
驱动通过 I2C sysfs 接口支持接口的热添加和移除。
IPMI IPMB 驱动¶
此驱动程序用于支持位于 IPMB 总线上的系统;它允许接口看起来像一个正常的 IPMI 接口。向其发送系统接口寻址的消息将导致消息发送到系统上已注册的 BMC(默认 IPMI 地址为 0x20)。
它还允许您使用 ipmb 直接寻址直接寻址总线上的其他 MC。您可以从总线上的其他 MC 接收命令,它们将通过上面描述的正常接收命令机制处理。
参数为:
ipmi_ipmb.bmcaddr=<address to use for system interface addresses messages>
ipmi_ipmb.retry_time_ms=<Time between retries on IPMB>
ipmi_ipmb.max_retries=<Number of times to retry a message>
除非有设备树信息进行设置,否则加载模块不会自动启动驱动。如果您想手动实例化其中一个,请执行以下操作:
echo ipmi-ipmb <addr> > /sys/class/i2c-dev/i2c-<n>/device/new_device
请注意,您在此处给出的地址是 I2C 地址,而不是 IPMI 地址。因此,如果您希望您的 MC 地址为 0x60,您在此处放置 0x30。有关更多详细信息,请参阅 I2C 驱动信息。
通过此接口向其他 IPMB 总线桥接命令不起作用。接收消息队列是按设计未实现的。BMC 上只有一个接收消息队列,它 предназначен用于主机驱动,而不是 IPMB 总线上的任何东西。
一个 BMC 可能有多个 IPMB 总线,您的设备位于哪个总线取决于系统的接线方式。您可以通过“ipmitool channel info <n>”获取通道,其中 <n> 是通道,通道范围为 0-7,并尝试 IPMB 通道。
其他部分¶
看门狗¶
提供了一个看门狗定时器,它实现了 Linux 标准的看门狗定时器接口。它有三个模块参数可以用来控制它:
modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
preaction=<preaction type> preop=<preop type> start_now=x
nowayout=x ifnum_to_use=n panic_wdt_timeout=<t>
ifnum_to_use 指定看门狗定时器应使用哪个接口。默认值为 -1,表示选择第一个注册的接口。
timeout 是到动作的秒数,pretimeout 是复位前发生预超时 panic 的秒数(如果 pretimeout 为零,则不启用 pretimeout)。请注意,pretimeout 是最终超时前的时间。因此,如果 timeout 是 50 秒,pretimeout 是 10 秒,那么 pretimeout 将在 40 秒(超时前 10 秒)发生。panic_wdt_timeout 是在内核 panic 时设置的 timeout 值,以便在 panic 期间执行 kdump 等操作。
action 可以是“reset”、“power_cycle”或“power_off”,指定定时器超时时执行的操作,默认为“reset”。
preaction 可以是“pre_smi”表示通过 SMI 接口指示,“pre_int”表示通过带中断的 SMI 指示,以及“pre_nmi”表示在预动作时发生 NMI。这是驱动如何得知预超时的。
preop 可以设置为“preop_none”表示预超时时无操作,“preop_panic”将预操作设置为 panic,或“preop_give_data”以在预超时发生时提供从看门狗设备读取的数据。“pre_nmi”设置不能与“preop_give_data”一起使用,因为无法从 NMI 执行数据操作。
当 preop 设置为“preop_give_data”时,预超时发生时,设备上会有一字节数据准备好读取。select 和 fasync 在设备上也能工作。
如果 start_now 设置为 1,则看门狗定时器将在驱动加载后立即开始运行。
如果 nowayout 设置为 1,则当看门狗设备关闭时,看门狗定时器不会停止。nowayout 的默认值是:如果 CONFIG_WATCHDOG_NOWAYOUT 选项启用,则为 true;否则为 false。
当编译到内核中时,内核命令行可用于配置看门狗:
ipmi_watchdog.timeout=<t> ipmi_watchdog.pretimeout=<t>
ipmi_watchdog.action=<action type>
ipmi_watchdog.preaction=<preaction type>
ipmi_watchdog.preop=<preop type>
ipmi_watchdog.start_now=x
ipmi_watchdog.nowayout=x
ipmi_watchdog.panic_wdt_timeout=<t>
这些选项与模块参数选项相同。
如果看门狗收到预动作,它将恐慌并启动一个 120 秒的复位超时。在恐慌或重启期间,如果看门狗正在运行,它将启动一个 120 秒的计时器,以确保重启发生。
请注意,如果您对看门狗使用 NMI 预动作,则绝不能使用 NMI 看门狗。没有合理的方法可以判断 NMI 是否来自 IPMI 控制器,因此它必须假定如果收到其他未处理的 NMI,它必然来自 IPMI,并且会立即恐慌。
一旦您打开看门狗定时器,您必须向设备写入一个“V”字符才能关闭它,否则定时器将不会停止。这是驱动的新语义,但使其与 Linux 中其他看门狗驱动保持一致。
Panic 超时¶
OpenIPMI 驱动支持在发生 panic 时将半自定义和自定义事件放入系统事件日志的功能。如果您启用“在 panic 时向所有 BMC 生成 panic 事件”选项,您将在 panic 时以标准 IPMI 事件格式获得一个事件。如果您启用“生成包含 panic 字符串的 OEM 事件”选项,您还将获得一堆包含 panic 字符串的 OEM 事件。
事件的字段设置是:
生成器 ID:0x21(内核)
EvM Rev:0x03(此事件以 IPMI 1.0 格式格式化)
传感器类型:0x20(操作系统关键停止传感器)
传感器编号:panic 字符串的第一个字节(如果没有 panic 字符串则为 0)
事件方向 | 事件类型:0x6f(断言,传感器特定事件信息)
事件数据 1:0xa1(OEM 字节 2 和 3 中的运行时停止)
事件数据 2:panic 字符串的第二个字节
事件数据 3:panic 字符串的第三个字节
有关事件布局的详细信息,请参阅 IPMI 规范。此事件总是发送到本地管理控制器。它将处理将消息路由到正确位置。
其他 OEM 事件具有以下格式:
记录 ID(字节 0-1):由 SEL 设置。
记录类型(字节 2):0xf0(OEM 无时间戳)
字节 3:保存 panic 的卡的从属地址
字节 4:序列号(从零开始)。其余字节(11 字节)是 panic 字符串。如果 panic 字符串长于 11 字节,将发送多个消息,序列号递增。
因为您无法使用标准接口发送 OEM 事件,所以此函数将尝试查找 SEL 并将事件添加到其中。它将首先查询本地管理控制器的功能。如果它有 SEL,那么事件将存储在本地管理控制器的 SEL 中。如果本地管理控制器不是事件生成器,将查询本地管理控制器的事件接收器,并将事件发送到该设备上的 SEL。否则,事件将无处可发送。
关机¶
如果选择了关机功能,IPMI 驱动将在标准关机函数指针中安装一个关机函数。这在 ipmi_poweroff 模块中。当系统请求关机时,它将发送适当的 IPMI 命令来执行此操作。这在多个平台上受支持。
有一个名为“poweroff_powercycle”的模块参数,可以为零(执行关机)或非零(执行电源循环,关闭系统电源,然后在几秒钟内重新开启)。设置 ipmi_poweroff.poweroff_control=x 将在内核命令行上执行相同的操作。该参数也可通过 /proc/sys/dev/ipmi/poweroff_powercycle 中的 proc 文件系统获取。请注意,如果系统不支持电源循环,它将始终执行关机操作。
“ifnum_to_use”参数指定关机代码应使用哪个接口。默认值为 -1,表示选择第一个注册的接口。
请注意,如果启用了 ACPI,系统将优先使用 ACPI 进行关机。