* @firmware_event_thread: ""
  * @fw_event_lock:
  * @fw_event_list: list of fw events
+ * @current_evet: current processing firmware event
+ * @fw_event_cleanup: set to one while cleaning up the fw events
  * @aen_event_read_flag: event log was read
  * @broadcast_aen_busy: broadcast aen waiting to be serviced
  * @shost_recovery: host reset in progress
        struct workqueue_struct *firmware_event_thread;
        spinlock_t      fw_event_lock;
        struct list_head fw_event_list;
+       struct fw_event_work    *current_event;
+       u8              fw_events_cleanup;
 
         /* misc flags */
        int             aen_event_read_flag;
 
 {
        struct fw_event_work *fw_event;
 
-       if (list_empty(&ioc->fw_event_list) ||
+       if ((list_empty(&ioc->fw_event_list) && !ioc->current_event) ||
             !ioc->firmware_event_thread || in_interrupt())
                return;
 
-       while ((fw_event = dequeue_next_fw_event(ioc))) {
+       ioc->fw_events_cleanup = 1;
+       while ((fw_event = dequeue_next_fw_event(ioc)) ||
+            (fw_event = ioc->current_event)) {
                /*
                 * Wait on the fw_event to complete. If this returns 1, then
                 * the event was never executed, and we need a put for the
 
                fw_event_work_put(fw_event);
        }
+       ioc->fw_events_cleanup = 0;
 }
 
 /**
 static void
 _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
 {
+       ioc->current_event = fw_event;
        _scsih_fw_event_del_from_list(ioc, fw_event);
 
        /* the queue is being flushed so ignore this event */
        if (ioc->remove_host || ioc->pci_error_recovery) {
                fw_event_work_put(fw_event);
+               ioc->current_event = NULL;
                return;
        }
 
                while (scsi_host_in_recovery(ioc->shost) ||
                                         ioc->shost_recovery) {
                        /*
-                        * If we're unloading, bail. Otherwise, this can become
-                        * an infinite loop.
+                        * If we're unloading or cancelling the work, bail.
+                        * Otherwise, this can become an infinite loop.
                         */
-                       if (ioc->remove_host)
+                       if (ioc->remove_host || ioc->fw_events_cleanup)
                                goto out;
                        ssleep(1);
                }
                break;
        case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
                _scsih_pcie_topology_change_event(ioc, fw_event);
+               ioc->current_event = NULL;
                        return;
        break;
        }
 out:
        fw_event_work_put(fw_event);
+       ioc->current_event = NULL;
 }
 
 /**