Index: uspace/drv/bus/usb/xhci/commands.c
===================================================================
--- uspace/drv/bus/usb/xhci/commands.c	(revision 309d98654eff661ee05c4e42c31dc8ad9bbdad58)
+++ uspace/drv/bus/usb/xhci/commands.c	(revision d2c3dcd880ba1b8f4263eddeaae18bcc6c072bd9)
@@ -168,4 +168,32 @@
 }
 
+static void cr_set_state(xhci_cmd_ring_t *cr, xhci_cr_state_t state)
+{
+	assert(fibril_mutex_is_locked(&cr->guard));
+
+	cr->state = state;
+	if (state == XHCI_CR_STATE_OPEN
+	    || state == XHCI_CR_STATE_CLOSED)
+		fibril_condvar_broadcast(&cr->state_cv);
+}
+
+static int wait_for_ring_open(xhci_cmd_ring_t *cr)
+{
+	assert(fibril_mutex_is_locked(&cr->guard));
+
+	while (true) {
+		switch (cr->state) {
+		case XHCI_CR_STATE_CHANGING:
+		case XHCI_CR_STATE_FULL:
+			fibril_condvar_wait(&cr->state_cv, &cr->guard);
+			break;
+		case XHCI_CR_STATE_OPEN:
+			return EOK;
+		case XHCI_CR_STATE_CLOSED:
+			return ENAK;
+		}
+	}
+}
+
 /**
  * Enqueue a command on the TRB ring. Ring the doorbell to initiate processing.
@@ -179,8 +207,5 @@
 	fibril_mutex_lock(&cr->guard);
 
-	while (cr->state == XHCI_CR_STATE_CHANGING)
-		fibril_condvar_wait(&cr->state_cv, &cr->guard);
-
-	if (cr->state != XHCI_CR_STATE_OPEN) {
+	if (wait_for_ring_open(cr)) {
 		fibril_mutex_unlock(&cr->guard);
 		return ENAK;
@@ -191,10 +216,21 @@
 	list_append(&cmd->_header.link, &cr->cmd_list);
 
-	xhci_trb_ring_enqueue(&cr->trb_ring, &cmd->_header.trb, &cmd->_header.trb_phys);
-	hc_ring_doorbell(hc, 0, 0);
+	int err = EOK;
+	while (err == EOK) {
+		err = xhci_trb_ring_enqueue(&cr->trb_ring,
+		    &cmd->_header.trb, &cmd->_header.trb_phys);
+		if (err != EAGAIN)
+			break;
+
+		cr_set_state(cr, XHCI_CR_STATE_FULL);
+		err = wait_for_ring_open(cr);
+	}
+
+	if (err == EOK)
+		hc_ring_doorbell(hc, 0, 0);
 
 	fibril_mutex_unlock(&cr->guard);
 
-	return EOK;
+	return err;
 }
 
@@ -210,6 +246,5 @@
 
 	// Prevent others from starting CR again.
-	cr->state = XHCI_CR_STATE_CLOSED;
-	fibril_condvar_broadcast(&cr->state_cv);
+	cr_set_state(cr, XHCI_CR_STATE_CLOSED);
 
 	XHCI_REG_SET(hc->op_regs, XHCI_OP_CS, 1);
@@ -299,7 +334,4 @@
 
 	int code = TRB_GET_CODE(*trb);
-	const uint64_t phys = TRB_GET_PHYS(*trb);
-
-	xhci_trb_ring_update_dequeue(&cr->trb_ring, phys);
 
 	if (code == XHCI_TRBC_COMMAND_RING_STOPPED) {
@@ -316,4 +348,10 @@
 		return EOK;
 	}
+
+	const uint64_t phys = TRB_GET_PHYS(*trb);
+	xhci_trb_ring_update_dequeue(&cr->trb_ring, phys);
+
+	if (cr->state == XHCI_CR_STATE_FULL)
+		cr_set_state(cr, XHCI_CR_STATE_OPEN);
 
 	xhci_cmd_t *command = find_command(hc, phys);
@@ -592,8 +630,10 @@
 	fibril_mutex_lock(&cr->guard);
 
-	if (cr->state != XHCI_CR_STATE_OPEN) {
-		// The CR is either stopped, or different fibril is already
-		// restarting it.
-		usb_log_debug2("Command ring already being stopped.");
+	if (cr->state == XHCI_CR_STATE_CLOSED) {
+		fibril_mutex_unlock(&cr->guard);
+		return ENAK;
+	}
+
+	if (cr->state == XHCI_CR_STATE_CHANGING) {
 		fibril_mutex_unlock(&cr->guard);
 		return EOK;
@@ -602,6 +642,5 @@
 	usb_log_error("Timeout while waiting for command: aborting current command.");
 
-	cr->state = XHCI_CR_STATE_CHANGING;
-	fibril_condvar_broadcast(&cr->state_cv);
+	cr_set_state(cr, XHCI_CR_STATE_CHANGING);
 
 	abort_command_ring(hc);
@@ -616,6 +655,5 @@
 		usb_log_error("Command didn't abort.");
 
-		cr->state = XHCI_CR_STATE_CLOSED;
-		fibril_condvar_broadcast(&cr->state_cv);
+		cr_set_state(cr, XHCI_CR_STATE_CLOSED);
 
 		// TODO: Reset HC completely.
@@ -626,11 +664,11 @@
 	}
 
+	cr_set_state(cr, XHCI_CR_STATE_OPEN);
+
+	fibril_mutex_unlock(&cr->guard);
+
 	usb_log_error("Command ring stopped. Starting again.");
 	hc_ring_doorbell(hc, 0, 0);
 
-	cr->state = XHCI_CR_STATE_OPEN;
-	fibril_condvar_broadcast(&cr->state_cv);
-
-	fibril_mutex_unlock(&cr->guard);
 	return EOK;
 }
Index: uspace/drv/bus/usb/xhci/commands.h
===================================================================
--- uspace/drv/bus/usb/xhci/commands.h	(revision 309d98654eff661ee05c4e42c31dc8ad9bbdad58)
+++ uspace/drv/bus/usb/xhci/commands.h	(revision d2c3dcd880ba1b8f4263eddeaae18bcc6c072bd9)
@@ -73,5 +73,6 @@
 	XHCI_CR_STATE_OPEN,		/**< Commands are enqueued normally. */
 	XHCI_CR_STATE_CHANGING,		/**< Commands wait until state changes. */
-} xhci_cr_state;
+	XHCI_CR_STATE_FULL,		/**< Commands wait until something completes. */
+} xhci_cr_state_t;
 
 typedef struct xhci_command_ring {
@@ -81,5 +82,5 @@
 	list_t cmd_list;
 
-	xhci_cr_state state;		/**< Whether commands are allowed to be
+	xhci_cr_state_t state;		/**< Whether commands are allowed to be
 					     added. */
 	fibril_condvar_t state_cv;	/**< For waiting on CR state change. */
