enum drbd_state_rv rv;
        if (force) {
                spin_lock_irq(&tconn->req_lock);
-               if (tconn->cstate >= C_WF_CONNECTION)
-                       _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+               rv = _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
                spin_unlock_irq(&tconn->req_lock);
-               return SS_SUCCESS;
+               return rv;
        }
 
        rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING), 0);
        if (rv < SS_SUCCESS)
                goto fail;
 
+       /* No one else can reconfigure the network while I am here.
+        * The state handling only uses drbd_thread_stop_nowait(),
+        * we want to really wait here until the receiver is no more. */
+       drbd_thread_stop(&tconn->receiver);
        if (wait_event_interruptible(tconn->ping_wait,
-                                    tconn->cstate != C_DISCONNECTING)) {
-               /* Do not test for mdev->state.conn == C_STANDALONE, since
-                  someone else might connect us in the mean time! */
+                                    tconn->cstate == C_STANDALONE)) {
                retcode = ERR_INTR;
                goto fail;
        }
                goto out_unlock;
        }
 
+       /* Make sure the network threads have actually stopped,
+        * state handling only does drbd_thread_stop_nowait(). */
+       drbd_thread_stop(&adm_ctx.tconn->receiver);
+
        /* detach */
        idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
                rv = adm_detach(mdev);
                }
        }
 
-       /* stop all threads */
-       conn_reconfig_done(adm_ctx.tconn);
-
        /* delete connection */
        if (conn_lowest_minor(adm_ctx.tconn) < 0) {
+               drbd_thread_stop(&adm_ctx.tconn->worker);
                list_del(&adm_ctx.tconn->all_tconn);
                kref_put(&adm_ctx.tconn->kref, &conn_destroy);
 
 
 static enum drbd_state_rv
 is_valid_conn_transition(enum drbd_conns oc, enum drbd_conns nc)
 {
-       enum drbd_state_rv rv = SS_SUCCESS;
+       /* no change -> nothing to do, at least for the connection part */
+       if (oc == nc)
+               return SS_NOTHING_TO_DO;
 
-       /* Disallow Network errors to configure a device's network part */
-       if ((nc >= C_TIMEOUT && nc <= C_TEAR_DOWN) && oc <= C_DISCONNECTING)
-               rv = SS_NEED_CONNECTION;
+       /* disconnect of an unconfigured connection does not make sense */
+       if (oc == C_STANDALONE && nc == C_DISCONNECTING)
+               return SS_ALREADY_STANDALONE;
+
+       /* from C_STANDALONE, we start with C_UNCONNECTED */
+       if (oc == C_STANDALONE && nc != C_UNCONNECTED)
+               return SS_NEED_CONNECTION;
 
        /* After a network error only C_UNCONNECTED or C_DISCONNECTING may follow. */
        if (oc >= C_TIMEOUT && oc <= C_TEAR_DOWN && nc != C_UNCONNECTED && nc != C_DISCONNECTING)
-               rv = SS_IN_TRANSIENT_STATE;
+               return SS_IN_TRANSIENT_STATE;
 
        /* After C_DISCONNECTING only C_STANDALONE may follow */
        if (oc == C_DISCONNECTING && nc != C_STANDALONE)
-               rv = SS_IN_TRANSIENT_STATE;
+               return SS_IN_TRANSIENT_STATE;
 
-       return rv;
+       return SS_SUCCESS;
 }