ids.port_name = rport->port_name;
                ids.node_name = rport->node_name;
 
+               rdata->event = RPORT_EV_NONE;
                mutex_unlock(&rdata->rp_mutex);
 
                new_rport = fc_remote_port_add(lport->host, 0, &ids);
        return 0;
 }
 
+/**
+ * fc_rport_enter_delete() - schedule a remote port to be deleted.
+ * @rport: Fibre Channel remote port
+ * @event: event to report as the reason for deletion
+ *
+ * Locking Note: Called with the rport lock held.
+ *
+ * Allow state change into DELETE only once.
+ *
+ * Call queue_work only if there's no event already pending.
+ * Set the new event so that the old pending event will not occur.
+ * Since we have the mutex, even if fc_rport_work() is already started,
+ * it'll see the new event.
+ */
+static void fc_rport_enter_delete(struct fc_rport *rport,
+                                 enum fc_rport_event event)
+{
+       struct fc_rport_libfc_priv *rdata = rport->dd_data;
+
+       if (rdata->rp_state == RPORT_ST_DELETE)
+               return;
+
+       FC_RPORT_DBG(rport, "Delete port\n");
+
+       fc_rport_state_enter(rport, RPORT_ST_DELETE);
+
+       if (rdata->event == RPORT_EV_NONE)
+               queue_work(rport_event_queue, &rdata->event_work);
+       rdata->event = event;
+}
+
 /**
  * fc_rport_logoff() - Logoff and remove an rport
  * @rport: Fibre Channel remote port to be removed
         * Change the state to Delete so that we discard
         * the response.
         */
-       fc_rport_state_enter(rport, RPORT_ST_DELETE);
-
-       mutex_unlock(&rdata->rp_mutex);
-
-       cancel_delayed_work_sync(&rdata->retry_work);
-
-       mutex_lock(&rdata->rp_mutex);
-
-       rdata->event = RPORT_EV_STOP;
-       queue_work(rport_event_queue, &rdata->event_work);
-
+       fc_rport_enter_delete(rport, RPORT_EV_STOP);
        mutex_unlock(&rdata->rp_mutex);
 
 out:
 
        FC_RPORT_DBG(rport, "Port is Ready\n");
 
+       if (rdata->event == RPORT_EV_NONE)
+               queue_work(rport_event_queue, &rdata->event_work);
        rdata->event = RPORT_EV_CREATED;
-       queue_work(rport_event_queue, &rdata->event_work);
 }
 
 /**
        case RPORT_ST_PLOGI:
        case RPORT_ST_PRLI:
        case RPORT_ST_LOGO:
-               rdata->event = RPORT_EV_FAILED;
-               fc_rport_state_enter(rport, RPORT_ST_DELETE);
-               queue_work(rport_event_queue,
-                          &rdata->event_work);
+               fc_rport_enter_delete(rport, RPORT_EV_FAILED);
                break;
        case RPORT_ST_RTV:
                fc_rport_enter_ready(rport);
 
        } else {
                FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n");
-               rdata->event = RPORT_EV_FAILED;
-               fc_rport_state_enter(rport, RPORT_ST_DELETE);
-               queue_work(rport_event_queue, &rdata->event_work);
+               fc_rport_enter_delete(rport, RPORT_EV_FAILED);
        }
 
 out:
                fc_rport_enter_rtv(rport);
        } else {
                FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n");
-               rdata->event = RPORT_EV_LOGO;
-               fc_rport_state_enter(rport, RPORT_ST_DELETE);
-               queue_work(rport_event_queue, &rdata->event_work);
+               fc_rport_enter_delete(rport, RPORT_EV_LOGO);
        }
 
 out: