[RPORT_ST_LOGO] = "LOGO",
        [RPORT_ST_ADISC] = "ADISC",
        [RPORT_ST_DELETE] = "Delete",
+       [RPORT_ST_RESTART] = "Restart",
 };
 
 /**
        struct fc_rport_priv *rdata;
 
        list_for_each_entry(rdata, &lport->disc.rports, peers)
-               if (rdata->ids.port_id == port_id &&
-                   rdata->rp_state != RPORT_ST_DELETE)
+               if (rdata->ids.port_id == port_id)
                        return rdata;
        return NULL;
 }
        struct fc_rport_operations *rport_ops;
        struct fc_rport_identifiers ids;
        struct fc_rport *rport;
+       int restart = 0;
 
        mutex_lock(&rdata->rp_mutex);
        event = rdata->event;
                mutex_unlock(&rdata->rp_mutex);
 
                if (port_id != FC_FID_DIR_SERV) {
+                       /*
+                        * We must drop rp_mutex before taking disc_mutex.
+                        * Re-evaluate state to allow for restart.
+                        * A transition to RESTART state must only happen
+                        * while disc_mutex is held and rdata is on the list.
+                        */
                        mutex_lock(&lport->disc.disc_mutex);
-                       list_del(&rdata->peers);
+                       mutex_lock(&rdata->rp_mutex);
+                       if (rdata->rp_state == RPORT_ST_RESTART)
+                               restart = 1;
+                       else
+                               list_del(&rdata->peers);
+                       mutex_unlock(&rdata->rp_mutex);
                        mutex_unlock(&lport->disc.disc_mutex);
                }
 
                        mutex_unlock(&rdata->rp_mutex);
                        fc_remote_port_delete(rport);
                }
-               kref_put(&rdata->kref, lport->tt.rport_destroy);
+               if (restart) {
+                       mutex_lock(&rdata->rp_mutex);
+                       FC_RPORT_DBG(rdata, "work restart\n");
+                       fc_rport_enter_plogi(rdata);
+                       mutex_unlock(&rdata->rp_mutex);
+               } else
+                       kref_put(&rdata->kref, lport->tt.rport_destroy);
                break;
 
        default:
                FC_RPORT_DBG(rdata, "ADISC port\n");
                fc_rport_enter_adisc(rdata);
                break;
+       case RPORT_ST_RESTART:
+               break;
+       case RPORT_ST_DELETE:
+               FC_RPORT_DBG(rdata, "Restart deleted port\n");
+               fc_rport_state_enter(rdata, RPORT_ST_RESTART);
+               break;
        default:
                FC_RPORT_DBG(rdata, "Login to port\n");
                fc_rport_enter_plogi(rdata);
 
        if (rdata->rp_state == RPORT_ST_DELETE) {
                FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
-               mutex_unlock(&rdata->rp_mutex);
                goto out;
        }
 
-       fc_rport_enter_logo(rdata);
+       if (rdata->rp_state == RPORT_ST_RESTART)
+               FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
+       else
+               fc_rport_enter_logo(rdata);
 
        /*
         * Change the state to Delete so that we discard
         * the response.
         */
        fc_rport_enter_delete(rdata, RPORT_EV_STOP);
-       mutex_unlock(&rdata->rp_mutex);
-
 out:
+       mutex_unlock(&rdata->rp_mutex);
        return 0;
 }
 
        case RPORT_ST_READY:
        case RPORT_ST_INIT:
        case RPORT_ST_DELETE:
+       case RPORT_ST_RESTART:
                break;
        }
 
                fc_rport_enter_logo(rdata);
                break;
        case RPORT_ST_DELETE:
+       case RPORT_ST_RESTART:
        case RPORT_ST_READY:
        case RPORT_ST_INIT:
                break;
                }
                break;
        case RPORT_ST_PRLI:
+       case RPORT_ST_RTV:
        case RPORT_ST_READY:
        case RPORT_ST_ADISC:
                FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
                /* XXX TBD - should reset */
                break;
        case RPORT_ST_DELETE:
-       default:
-               FC_RPORT_DBG(rdata, "Received PLOGI in unexpected state %d\n",
-                            rdata->rp_state);
-               fc_frame_free(rx_fp);
-               goto out;
+       case RPORT_ST_LOGO:
+       case RPORT_ST_RESTART:
+               FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
+                            fc_rport_state(rdata));
+               mutex_unlock(&rdata->rp_mutex);
+               rjt_data.reason = ELS_RJT_BUSY;
+               rjt_data.explan = ELS_EXPL_NONE;
+               goto reject;
        }
 
        /*
                FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
                             fc_rport_state(rdata));
 
+               fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+
                /*
-                * If the remote port was created due to discovery,
-                * log back in.  It may have seen a stale RSCN about us.
+                * If the remote port was created due to discovery, set state
+                * to log back in.  It may have seen a stale RSCN about us.
                 */
-               if (rdata->rp_state != RPORT_ST_DELETE && rdata->disc_id)
-                       fc_rport_enter_plogi(rdata);
-               else
-                       fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+               if (rdata->disc_id)
+                       fc_rport_state_enter(rdata, RPORT_ST_RESTART);
                mutex_unlock(&rdata->rp_mutex);
        } else
                FC_RPORT_ID_DBG(lport, sid,