ipmi: Differentiate between reset and firmware update in maintenance

This allows later changes to have different behaviour during a reset
verses a firmware update.

Signed-off-by: Corey Minyard <corey@minyard.net>
Tested-by: Frederick Lawler <fred@cloudflare.com>
pull/1354/merge
Corey Minyard 2025-08-07 15:54:20 -05:00
parent 121f4a7e47
commit e5feb030d9
1 changed files with 30 additions and 12 deletions

View File

@ -541,7 +541,11 @@ struct ipmi_smi {
/* For handling of maintenance mode. */
int maintenance_mode;
bool maintenance_mode_enable;
#define IPMI_MAINTENANCE_MODE_STATE_OFF 0
#define IPMI_MAINTENANCE_MODE_STATE_FIRMWARE 1
#define IPMI_MAINTENANCE_MODE_STATE_RESET 2
int maintenance_mode_state;
int auto_maintenance_timeout;
spinlock_t maintenance_mode_lock; /* Used in a timer... */
@ -1530,8 +1534,15 @@ EXPORT_SYMBOL(ipmi_get_maintenance_mode);
static void maintenance_mode_update(struct ipmi_smi *intf)
{
if (intf->handlers->set_maintenance_mode)
/*
* Lower level drivers only care about firmware mode
* as it affects their timing. They don't care about
* reset, which disables all commands for a while.
*/
intf->handlers->set_maintenance_mode(
intf->send_info, intf->maintenance_mode_enable);
intf->send_info,
(intf->maintenance_mode_state ==
IPMI_MAINTENANCE_MODE_STATE_FIRMWARE));
}
int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode)
@ -1548,16 +1559,17 @@ int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode)
if (intf->maintenance_mode != mode) {
switch (mode) {
case IPMI_MAINTENANCE_MODE_AUTO:
intf->maintenance_mode_enable
= (intf->auto_maintenance_timeout > 0);
/* Just leave it alone. */
break;
case IPMI_MAINTENANCE_MODE_OFF:
intf->maintenance_mode_enable = false;
intf->maintenance_mode_state =
IPMI_MAINTENANCE_MODE_STATE_OFF;
break;
case IPMI_MAINTENANCE_MODE_ON:
intf->maintenance_mode_enable = true;
intf->maintenance_mode_state =
IPMI_MAINTENANCE_MODE_STATE_FIRMWARE;
break;
default:
@ -1917,13 +1929,18 @@ static int i_ipmi_req_sysintf(struct ipmi_smi *intf,
if (is_maintenance_mode_cmd(msg)) {
unsigned long flags;
int newst;
if (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)
newst = IPMI_MAINTENANCE_MODE_STATE_FIRMWARE;
else
newst = IPMI_MAINTENANCE_MODE_STATE_RESET;
spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
intf->auto_maintenance_timeout
= maintenance_mode_timeout_ms;
intf->auto_maintenance_timeout = maintenance_mode_timeout_ms;
if (!intf->maintenance_mode
&& !intf->maintenance_mode_enable) {
intf->maintenance_mode_enable = true;
&& intf->maintenance_mode_state < newst) {
intf->maintenance_mode_state = newst;
maintenance_mode_update(intf);
}
spin_unlock_irqrestore(&intf->maintenance_mode_lock,
@ -5028,7 +5045,8 @@ static bool ipmi_timeout_handler(struct ipmi_smi *intf,
-= timeout_period;
if (!intf->maintenance_mode
&& (intf->auto_maintenance_timeout <= 0)) {
intf->maintenance_mode_enable = false;
intf->maintenance_mode_state =
IPMI_MAINTENANCE_MODE_STATE_OFF;
maintenance_mode_update(intf);
}
}
@ -5044,7 +5062,7 @@ static bool ipmi_timeout_handler(struct ipmi_smi *intf,
static void ipmi_request_event(struct ipmi_smi *intf)
{
/* No event requests when in maintenance mode. */
if (intf->maintenance_mode_enable)
if (intf->maintenance_mode_state)
return;
if (!intf->in_shutdown)