ipmi: Allow an SMI sender to return an error
authorCorey Minyard <corey@minyard.net>
Wed, 20 Aug 2025 19:04:24 +0000 (14:04 -0500)
committerCorey Minyard <corey@minyard.net>
Mon, 8 Sep 2025 15:21:41 +0000 (10:21 -0500)
Getting ready for handling when a BMC is non-responsive or broken, allow
the sender operation to fail in an SMI.  If it was a user-generated
message it will return the error.

The powernv code was already doing this internally, but the way it was
written could result in deep stack descent if there were a lot of
messages queued.  Have its send return an error in this case.

Signed-off-by: Corey Minyard <corey@minyard.net>
drivers/char/ipmi/ipmi_ipmb.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_powernv.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_ssif.c
include/linux/ipmi_smi.h

index 6a4f279..3a51e58 100644 (file)
@@ -404,8 +404,7 @@ static void ipmi_ipmb_shutdown(void *send_info)
        ipmi_ipmb_stop_thread(iidev);
 }
 
-static void ipmi_ipmb_sender(void *send_info,
-                            struct ipmi_smi_msg *msg)
+static int ipmi_ipmb_sender(void *send_info, struct ipmi_smi_msg *msg)
 {
        struct ipmi_ipmb_dev *iidev = send_info;
        unsigned long flags;
@@ -417,6 +416,7 @@ static void ipmi_ipmb_sender(void *send_info,
        spin_unlock_irqrestore(&iidev->lock, flags);
 
        up(&iidev->wake_thread);
+       return IPMI_CC_NO_ERROR;
 }
 
 static void ipmi_ipmb_request_events(void *send_info)
index c6a5673..a739c88 100644 (file)
@@ -4803,6 +4803,7 @@ static void smi_work(struct work_struct *t)
        int run_to_completion = READ_ONCE(intf->run_to_completion);
        struct ipmi_smi_msg *newmsg = NULL;
        struct ipmi_recv_msg *msg, *msg2;
+       int cc;
 
        /*
         * Start the next message if available.
@@ -4811,7 +4812,7 @@ static void smi_work(struct work_struct *t)
         * because the lower layer is allowed to hold locks while calling
         * message delivery.
         */
-
+restart:
        if (!run_to_completion)
                spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
        if (intf->curr_msg == NULL && !intf->in_shutdown) {
@@ -4832,8 +4833,17 @@ static void smi_work(struct work_struct *t)
        if (!run_to_completion)
                spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
 
-       if (newmsg)
-               intf->handlers->sender(intf->send_info, newmsg);
+       if (newmsg) {
+               cc = intf->handlers->sender(intf->send_info, newmsg);
+               if (cc) {
+                       if (newmsg->user_data)
+                               deliver_err_response(intf,
+                                                    newmsg->user_data, cc);
+                       else
+                               ipmi_free_smi_msg(newmsg);
+                       goto restart;
+               }
+       }
 
        handle_new_recv_msgs(intf);
 
index 4a2efaf..52a1130 100644 (file)
@@ -51,7 +51,7 @@ static void send_error_reply(struct ipmi_smi_powernv *smi,
        ipmi_smi_msg_received(smi->intf, msg);
 }
 
-static void ipmi_powernv_send(void *send_info, struct ipmi_smi_msg *msg)
+static int ipmi_powernv_send(void *send_info, struct ipmi_smi_msg *msg)
 {
        struct ipmi_smi_powernv *smi = send_info;
        struct opal_ipmi_msg *opal_msg;
@@ -93,18 +93,19 @@ static void ipmi_powernv_send(void *send_info, struct ipmi_smi_msg *msg)
                        smi->interface_id, opal_msg, size);
        rc = opal_ipmi_send(smi->interface_id, opal_msg, size);
        pr_devel("%s:  -> %d\n", __func__, rc);
-
-       if (!rc) {
-               smi->cur_msg = msg;
-               spin_unlock_irqrestore(&smi->msg_lock, flags);
-               return;
+       if (rc) {
+               comp = IPMI_ERR_UNSPECIFIED;
+               goto err_unlock;
        }
 
-       comp = IPMI_ERR_UNSPECIFIED;
+       smi->cur_msg = msg;
+       spin_unlock_irqrestore(&smi->msg_lock, flags);
+       return IPMI_CC_NO_ERROR;
+
 err_unlock:
        spin_unlock_irqrestore(&smi->msg_lock, flags);
 err:
-       send_error_reply(smi, msg, comp);
+       return comp;
 }
 
 static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi)
index 7b2ba31..88d62ef 100644 (file)
@@ -809,8 +809,6 @@ restart:
         * this if there is not yet an upper layer to handle anything.
         */
        if (si_sm_result == SI_SM_ATTN || smi_info->got_attn) {
-               unsigned char msg[2];
-
                if (smi_info->si_state != SI_NORMAL) {
                        /*
                         * We got an ATTN, but we are doing something else.
@@ -907,8 +905,7 @@ static void flush_messages(void *send_info)
        }
 }
 
-static void sender(void                *send_info,
-                  struct ipmi_smi_msg *msg)
+static int sender(void *send_info, struct ipmi_smi_msg *msg)
 {
        struct smi_info   *smi_info = send_info;
        unsigned long     flags;
@@ -921,7 +918,7 @@ static void sender(void                *send_info,
                 * layer will call flush_messages to clear it out.
                 */
                smi_info->waiting_msg = msg;
-               return;
+               return IPMI_CC_NO_ERROR;
        }
 
        spin_lock_irqsave(&smi_info->si_lock, flags);
@@ -936,6 +933,7 @@ static void sender(void                *send_info,
        smi_info->waiting_msg = msg;
        check_start_timer_thread(smi_info);
        spin_unlock_irqrestore(&smi_info->si_lock, flags);
+       return IPMI_CC_NO_ERROR;
 }
 
 static void set_run_to_completion(void *send_info, bool i_run_to_completion)
index 1bc4283..1b63f7d 100644 (file)
@@ -1068,8 +1068,7 @@ static void start_next_msg(struct ssif_info *ssif_info, unsigned long *flags)
        }
 }
 
-static void sender(void                *send_info,
-                  struct ipmi_smi_msg *msg)
+static int sender(void *send_info, struct ipmi_smi_msg *msg)
 {
        struct ssif_info *ssif_info = send_info;
        unsigned long oflags, *flags;
@@ -1089,6 +1088,7 @@ static void sender(void                *send_info,
                        msg->data[0], msg->data[1],
                        (long long)t.tv_sec, (long)t.tv_nsec / NSEC_PER_USEC);
        }
+       return IPMI_CC_NO_ERROR;
 }
 
 static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
index 5d69820..c2d975b 100644 (file)
@@ -109,8 +109,8 @@ struct ipmi_smi_msg {
 
        enum ipmi_smi_msg_type type;
 
-       long    msgid;
-       void    *user_data;
+       long msgid;
+       void *user_data;
 
        int           data_size;
        unsigned char data[IPMI_MAX_MSG_LENGTH];
@@ -168,9 +168,11 @@ struct ipmi_smi_handlers {
         * are held when this is run.  Message are delivered one at
         * a time by the message handler, a new message will not be
         * delivered until the previous message is returned.
+        *
+        * This can return an error if the SMI is not in a state where it
+        * can send a message.
         */
-       void (*sender)(void                *send_info,
-                      struct ipmi_smi_msg *msg);
+       int (*sender)(void *send_info, struct ipmi_smi_msg *msg);
 
        /*
         * Called by the upper layer to request that we try to get