ipmi: Differentiate between reset and firmware update in maintenance
authorCorey Minyard <corey@minyard.net>
Thu, 7 Aug 2025 20:54:20 +0000 (15:54 -0500)
committerCorey Minyard <corey@minyard.net>
Mon, 8 Sep 2025 15:21:40 +0000 (10:21 -0500)
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>
drivers/char/ipmi/ipmi_msghandler.c

index d2fbf22..18266ba 100644 (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)