#include <linux/uuid.h>
 #include <linux/nospec.h>
 #include <linux/vmalloc.h>
+#include <linux/delay.h>
 
 #define IPMI_DRIVER_VERSION "39.2"
 
 #else
 #define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_NONE
 #endif
+
+#define GET_DEVICE_ID_MAX_RETRY        5
+
 static enum ipmi_panic_event_op ipmi_send_panic_event = IPMI_PANIC_DEFAULT;
 
 static int panic_op_write_handler(const char *val,
        int                    dyn_guid_set;
        struct kref            usecount;
        struct work_struct     remove_work;
+       char                   cc; /* completion code */
 };
 #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev)
 
                        msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id);
        if (rv) {
                dev_warn(intf->si_dev, "device id demangle failed: %d\n", rv);
+               /* record completion code when error */
+               intf->bmc->cc = msg->msg.data[0];
                intf->bmc->dyn_id_set = 0;
        } else {
                /*
 static int __get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc)
 {
        int rv;
-
-       bmc->dyn_id_set = 2;
+       unsigned int retry_count = 0;
 
        intf->null_user_handler = bmc_device_id_handler;
 
+retry:
+       bmc->cc = 0;
+       bmc->dyn_id_set = 2;
+
        rv = send_get_device_id_cmd(intf);
        if (rv)
                goto out_reset_handler;
 
        wait_event(intf->waitq, bmc->dyn_id_set != 2);
 
-       if (!bmc->dyn_id_set)
+       if (!bmc->dyn_id_set) {
+               if ((bmc->cc == IPMI_DEVICE_IN_FW_UPDATE_ERR
+                    || bmc->cc ==  IPMI_DEVICE_IN_INIT_ERR
+                    || bmc->cc ==  IPMI_NOT_IN_MY_STATE_ERR)
+                    && ++retry_count <= GET_DEVICE_ID_MAX_RETRY) {
+                       msleep(500);
+                       dev_warn(intf->si_dev,
+                           "BMC returned 0x%2.2x, retry get bmc device id\n",
+                           bmc->cc);
+                       goto retry;
+               }
+
                rv = -EIO; /* Something went wrong in the fetch. */
+       }
 
        /* dyn_id_set makes the id data available. */
        smp_rmb();
                /* It's the one we want */
                if (msg->msg.data[0] != 0) {
                        /* Got an error from the channel, just go on. */
-
                        if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
                                /*
                                 * If the MC does not support this
 
 #define IPMI_ERR_MSG_TRUNCATED         0xc6
 #define IPMI_REQ_LEN_INVALID_ERR       0xc7
 #define IPMI_REQ_LEN_EXCEEDED_ERR      0xc8
+#define IPMI_DEVICE_IN_FW_UPDATE_ERR   0xd1
+#define IPMI_DEVICE_IN_INIT_ERR                0xd2
 #define IPMI_NOT_IN_MY_STATE_ERR       0xd5    /* IPMI 2.0 */
 #define IPMI_LOST_ARBITRATION_ERR      0x81
 #define IPMI_BUS_ERR                   0x82