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/APCI 信息错误或不存在,请准备好尝试进行一些计算,看看它是否可以在您的系统上工作。同时启用这两个选项并让驱动程序自动检测存在的内容是相当安全的。
您通常应该在系统上启用 ACPI,因为带有 IPMI 的系统可以具有描述它们的 ACPI 表。
如果您有一个标准接口并且主板制造商正确完成了他们的工作,则应自动检测到 IPMI 控制器(通过 ACPI 或 SMBIOS 表),并且应该可以正常工作。遗憾的是,许多板卡都没有此信息。驱动程序会尝试使用标准默认值,但它们可能无法工作。如果您遇到这种情况,您需要阅读下面名为“SI 驱动程序”或“SMBus 驱动程序”的部分,了解如何手动配置您的系统。
IPMI 定义了一个标准看门狗定时器。您可以使用“IPMI 看门狗定时器”配置选项启用此功能。如果您将驱动程序编译到内核中,则可以通过内核命令行选项使看门狗定时器在初始化后立即启动。它还有很多其他选项,请参阅下面的“看门狗”部分了解更多详细信息。请注意,如果看门狗关闭,您也可以让看门狗继续运行(默认情况下,关闭时禁用它)。进入“看门狗卡”菜单,启用“看门狗定时器支持”,并启用选项“关闭时禁用看门狗关闭”。
IPMI 系统通常可以使用 IPMI 命令关闭电源。选择“IPMI Poweroff”来执行此操作。该驱动程序将自动检测系统是否可以通过 IPMI 关闭电源。即使您的系统不支持此选项,启用此选项也是安全的。这适用于 ATCA 系统、Radisys CPI1 卡以及任何支持标准机箱管理命令的 IPMI 系统。
如果您希望驱动程序在发生 panic 时将事件放入事件日志中,请启用“在 panic 时向所有 BMC 生成 panic 事件”选项。如果您希望使用 OEM 事件将整个 panic 字符串放入事件日志中,请启用“生成包含 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 上使用,以提供与主机的接口。
这些都可以通过配置选项单独选择。
接口的许多文档都在 include 文件中。IPMI include 文件是
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;
};
这里的“通道”通常为零,但有些设备支持多个通道,它对应于 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_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() 来获取它们,您必须使用 ipmi_recv_t 结构调用 IPMICTL_RECEIVE_MSG 才能实际获取消息。请记住,您必须在 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/通道只能注册一个用户,但不同的用户可以注册不同的命令,或者如果通道位掩码不重叠,则可以注册同一命令。
要响应接收到的命令,请设置返回的 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。
如果为接口指定端口为非零,则驱动程序将使用给定的 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 对于 hotmod 很有用,但显然仅对模块有用。
当编译到内核中时,可以在内核命令行上指定参数,如下所示:
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”s 是
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 地址。适配器是适配器的字符串名称,如 /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 设备有害。强烈建议在 smb_addr 参数中将已知的 I2C 地址提供给 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 崩溃事件、在崩溃时延长看门狗或在没有特殊内核补丁和驱动程序修改的情况下进行其他与崩溃相关的 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 是重置前将发生预超时崩溃的秒数(如果 pretimeout 为零,则将不启用预超时)。请注意,预超时是最终超时之前的时间。因此,如果超时时间为 50 秒,预超时时间为 10 秒,则预超时将发生在 40 秒(超时前 10 秒)。panic_wdt_timeout 是在内核崩溃时设置的超时值,以便在崩溃期间执行 kdump 等操作。
action 可以是 “reset”、“power_cycle” 或 “power_off”,指定在定时器超时时要执行的操作,默认为 “reset”。
preaction 可以是 “pre_smi”,表示通过 SMI 接口指示;“pre_int”,表示通过带有中断的 SMI 指示;以及 “pre_nmi”,表示在预操作时使用 NMI。这是驱动程序获知预超时的方式。
preop 可以设置为 “preop_none” 以在预超时时不进行任何操作,设置为 “preop_panic” 以将预操作设置为崩溃,或者设置为 “preop_give_data” 以在发生预超时时提供从看门狗设备读取的数据。 “pre_nmi” 设置不能与 “preop_give_data” 一起使用,因为您无法从 NMI 执行数据操作。
当 preop 设置为 “preop_give_data” 时,预超时发生时,设备上会准备好读取一个字节。Select 和 fasync 也可在设备上使用。
如果 start_now 设置为 1,则看门狗定时器将在驱动程序加载后立即开始运行。
如果 nowayout 设置为 1,则看门狗设备关闭时,看门狗定时器将不会停止。如果启用 CONFIG_WATCHDOG_NOWAYOUT 选项,则 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 中的其他看门狗驱动程序保持一致。
崩溃超时¶
如果发生崩溃,OpenIPMI 驱动程序支持在系统事件日志中放置半自定义和自定义事件。如果您启用 “在崩溃时向所有 BMC 生成崩溃事件” 选项,则在崩溃时将收到一个标准 IPMI 事件格式的事件。如果您启用 “生成包含崩溃字符串的 OEM 事件” 选项,您还将收到一堆包含崩溃字符串的 OEM 事件。
事件的字段设置为:
生成器 ID:0x21(内核)
EvM Rev:0x03(此事件以 IPMI 1.0 格式格式化)
传感器类型:0x20(OS 严重停止传感器)
传感器编号:崩溃字符串的第一个字节(如果没有崩溃字符串,则为 0)
事件方向 | 事件类型:0x6f(断言,特定于传感器的事件信息)
事件数据 1:0xa1(OEM 字节 2 和 3 中的运行时停止)
事件数据 2:崩溃字符串的第二个字节
事件数据 3:崩溃字符串的第三个字节
有关事件布局的详细信息,请参阅 IPMI 规范。此事件始终发送到本地管理控制器。它将处理将消息路由到正确的位置
其他 OEM 事件具有以下格式:
记录 ID(字节 0-1):由 SEL 设置。
记录类型(字节 2):0xf0(OEM 非时间戳)
字节 3:保存崩溃的卡的从属地址
字节 4:一个序列号(从零开始)其余字节(11 个字节)是崩溃字符串。如果崩溃字符串长于 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 关闭电源。