Index: generic/include/ipc/ipc.h
===================================================================
--- generic/include/ipc/ipc.h	(revision 7669bcf004fbab71b35a1a9ec2b476fb2c698b7a)
+++ generic/include/ipc/ipc.h	(revision eb3d3796fe70e08b188cec351b1979d97243c33f)
@@ -179,8 +179,10 @@
 
 typedef enum {
-	IPC_BUSY_FREE = 0,
-	IPC_BUSY_CONNECTING,
-	IPC_BUSY_CONNECTED
-} ipc_busy_t;
+	IPC_PHONE_FREE = 0,     /**< Phone is free and can be allocated */
+	IPC_PHONE_CONNECTING,   /**< Phone is connecting somewhere */
+	IPC_PHONE_CONNECTED,    /**< Phone is connected */
+	IPC_PHONE_HUNGUP,  /**< Phone is hung up, waiting for answers to come */
+	IPC_PHONE_SLAMMED       /**< Phone was hungup from server */
+} ipc_phone_state_t;
 
 struct phone_s {
@@ -188,5 +190,5 @@
 	link_t list;
 	answerbox_t *callee;
-	ipc_busy_t busy;
+	ipc_phone_state_t state;
 	atomic_t active_calls;
 };
@@ -223,5 +225,5 @@
 extern int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox);
 extern void ipc_cleanup(task_t *task);
-extern int ipc_phone_hangup(phone_t *phone);
+extern int ipc_phone_hangup(phone_t *phone, int aggressive);
 extern void ipc_backsend_err(phone_t *phone, call_t *call, __native err);
 
Index: generic/include/proc/task.h
===================================================================
--- generic/include/proc/task.h	(revision 7669bcf004fbab71b35a1a9ec2b476fb2c698b7a)
+++ generic/include/proc/task.h	(revision eb3d3796fe70e08b188cec351b1979d97243c33f)
@@ -52,5 +52,7 @@
 	answerbox_t answerbox;  /**< Communication endpoint */
 	phone_t phones[IPC_MAX_PHONES];
-	atomic_t active_calls;  /**< Active asynchronous messages */
+	atomic_t active_calls;  /**< Active asynchronous messages.
+				 *   It is used for limiting uspace to
+				 *   certain extent. */
 	
 	task_arch_t arch;	/**< Architecture specific task data. */
Index: generic/src/ipc/ipc.c
===================================================================
--- generic/src/ipc/ipc.c	(revision 7669bcf004fbab71b35a1a9ec2b476fb2c698b7a)
+++ generic/src/ipc/ipc.c	(revision eb3d3796fe70e08b188cec351b1979d97243c33f)
@@ -112,5 +112,5 @@
 
 	ASSERT(!phone->callee);
-	phone->busy = IPC_BUSY_CONNECTED;
+	phone->state = IPC_PHONE_CONNECTED;
 	phone->callee = box;
 
@@ -128,5 +128,5 @@
 	spinlock_initialize(&phone->lock, "phone_lock");
 	phone->callee = NULL;
-	phone->busy = IPC_BUSY_FREE;
+	phone->state = IPC_PHONE_FREE;
 	atomic_set(&phone->active_calls, 0);
 }
@@ -185,9 +185,5 @@
 	call->data.phone = phone;
 	atomic_inc(&phone->active_calls);
-	if (phone->busy == IPC_BUSY_CONNECTED)
-		IPC_SET_RETVAL(call->data, EHANGUP);
-	else
-		IPC_SET_RETVAL(call->data, ENOENT);
-
+	IPC_SET_RETVAL(call->data, err);
 	_ipc_answer_free_call(call);
 }
@@ -217,21 +213,18 @@
 
 	spinlock_lock(&phone->lock);
-
-	box = phone->callee;
-	if (!box) {
-		/* Trying to send over disconnected phone */
+	if (phone->state != IPC_PHONE_CONNECTED) {
 		spinlock_unlock(&phone->lock);
 		if (call->flags & IPC_CALL_FORWARDED) {
 			IPC_SET_RETVAL(call->data, EFORWARD);
 			_ipc_answer_free_call(call);
-		} else { /* Simulate sending back a message */
-			if (phone->busy == IPC_BUSY_CONNECTED)
+		} else {
+			if (phone->state == IPC_PHONE_HUNGUP)
 				ipc_backsend_err(phone, call, EHANGUP);
 			else
 				ipc_backsend_err(phone, call, ENOENT);
 		}
-
 		return ENOENT;
 	}
+	box = phone->callee;
 	_ipc_call(phone, box, call);
 	
@@ -242,9 +235,17 @@
 /** Disconnect phone from answerbox
  *
- * It is allowed to call disconnect on already disconnected phone
- *
+ * This call leaves the phone in HUNGUP state. The change to 'free' is done
+ * lazily later.
+ *
+ * @param phone Phone to be hung up
+ * @param aggressive If false, the phone is only marked hungup, and all 
+ *              messages are allowed to complete.
+ *              If true, all messages in all queues are discarded. There
+ *              may still be some messages that will be 'in-transit' on 
+ *              other CPU.
+ *              
  * @return 0 - phone disconnected, -1 - the phone was already disconnected
  */
-int ipc_phone_hangup(phone_t *phone)
+int ipc_phone_hangup(phone_t *phone, int aggressive)
 {
 	answerbox_t *box;
@@ -252,28 +253,31 @@
 	
 	spinlock_lock(&phone->lock);
+	if (phone->state == IPC_PHONE_FREE || phone->state ==IPC_PHONE_HUNGUP \
+	    || phone->state == IPC_PHONE_CONNECTING) {
+		spinlock_unlock(&phone->lock);
+		return -1;
+	}
 	box = phone->callee;
-	if (!box) {
-		if (phone->busy == IPC_BUSY_CONNECTING) {
-			spinlock_unlock(&phone->lock);
-			return -1;
+	if (phone->state != IPC_PHONE_SLAMMED) {
+		/* Remove myself from answerbox */
+		spinlock_lock(&box->lock);
+		list_remove(&phone->list);
+		spinlock_unlock(&box->lock);
+
+		if (phone->state != IPC_PHONE_SLAMMED) {
+			call = ipc_call_alloc(0);
+			IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
+			call->flags |= IPC_CALL_DISCARD_ANSWER;
+			_ipc_call(phone, box, call);
 		}
-		/* Already disconnected phone */
-		phone->busy = IPC_BUSY_FREE;
-		spinlock_unlock(&phone->lock);
-		return 0;
-	}
-
-	spinlock_lock(&box->lock);
-	list_remove(&phone->list);
-	phone->callee = NULL;
-	spinlock_unlock(&box->lock);
-
-	call = ipc_call_alloc(0);
-	IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
-	call->flags |= IPC_CALL_DISCARD_ANSWER;
-	_ipc_call(phone, box, call);
-
-	phone->busy = IPC_BUSY_FREE;
-
+	}
+
+	if (aggressive && atomic_get(&phone->active_calls) > 0) {
+		/* TODO: Do some stuff be VERY aggressive */
+	}
+
+	phone->callee = 0;
+	
+	phone->state = IPC_PHONE_HUNGUP;
 	spinlock_unlock(&phone->lock);
 
@@ -381,5 +385,5 @@
 	/* Disconnect all our phones ('ipc_phone_hangup') */
 	for (i=0;i < IPC_MAX_PHONES; i++)
-		ipc_phone_hangup(&task->phones[i]);
+		ipc_phone_hangup(&task->phones[i], 1);
 
 	/* Disconnect all connected irqs */
@@ -399,5 +403,6 @@
 		
 		/* Disconnect phone */
-		phone->callee = NULL;
+		ASSERT(phone->state == IPC_PHONE_CONNECTED);
+		phone->state = IPC_PHONE_SLAMMED;
 		list_remove(&phone->list);
 
@@ -412,5 +417,19 @@
 	
 	/* Wait for all async answers to arrive */
-	while (atomic_get(&task->active_calls)) {
+	while (1) {
+		/* Go through all phones, until all are FREE... */
+		/* Locking not needed, no one else should modify
+		 * it, when we are in cleanup */
+		for (i=0;i < IPC_MAX_PHONES; i++) {
+			if (task->phones[i].state == IPC_PHONE_HUNGUP && \
+			    atomic_get(&task->phones[i].active_calls) == 0)
+				task->phones[i].state = IPC_PHONE_FREE;
+			if (task->phones[i].state != IPC_PHONE_FREE)
+				break;
+		}
+		/* Voila, got into cleanup */
+		if (i == IPC_MAX_PHONES)
+			break;
+		
 		call = ipc_wait_for_call(&task->answerbox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
 		ASSERT((call->flags & IPC_CALL_ANSWERED) || (call->flags & IPC_CALL_NOTIF));
Index: generic/src/ipc/ipcrsc.c
===================================================================
--- generic/src/ipc/ipcrsc.c	(revision 7669bcf004fbab71b35a1a9ec2b476fb2c698b7a)
+++ generic/src/ipc/ipcrsc.c	(revision eb3d3796fe70e08b188cec351b1979d97243c33f)
@@ -159,6 +159,10 @@
 	
 	for (i=0; i < IPC_MAX_PHONES; i++) {
-		if (TASK->phones[i].busy==IPC_BUSY_FREE && !atomic_get(&TASK->phones[i].active_calls)) {
-			TASK->phones[i].busy = IPC_BUSY_CONNECTING;
+		if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \
+		    atomic_get(&TASK->phones[i].active_calls) == 0)
+			TASK->phones[i].state = IPC_PHONE_FREE;
+
+		if (TASK->phones[i].state == IPC_PHONE_FREE) {
+			TASK->phones[i].state = IPC_PHONE_CONNECTING;
 			break;
 		}
@@ -173,9 +177,9 @@
 static void phone_deallocp(phone_t *phone)
 {
-	ASSERT(phone->busy == IPC_BUSY_CONNECTING);
+	ASSERT(phone->state == IPC_PHONE_CONNECTING);
 	ASSERT(! phone->callee);
 	
 	/* atomic operation */
-	phone->busy = IPC_BUSY_FREE;
+	phone->state = IPC_PHONE_FREE;
 }
 
@@ -201,5 +205,5 @@
 	phone_t *phone = &TASK->phones[phoneid];
 	
-	ASSERT(phone->busy == IPC_BUSY_CONNECTING);
+	ASSERT(phone->state == IPC_PHONE_CONNECTING);
 	ipc_phone_connect(phone, box);
 }
Index: generic/src/ipc/sysipc.c
===================================================================
--- generic/src/ipc/sysipc.c	(revision 7669bcf004fbab71b35a1a9ec2b476fb2c698b7a)
+++ generic/src/ipc/sysipc.c	(revision eb3d3796fe70e08b188cec351b1979d97243c33f)
@@ -106,7 +106,7 @@
 		spinlock_lock(&answer->data.phone->lock);
 		spinlock_lock(&TASK->answerbox.lock);
-		if (answer->data.phone->callee) {
+		if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
 			list_remove(&answer->data.phone->list);
-			answer->data.phone->callee = 0;
+			answer->data.phone->state = IPC_PHONE_SLAMMED;
 		}
 		spinlock_unlock(&TASK->answerbox.lock);
@@ -493,5 +493,5 @@
 	GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
-	if (ipc_phone_hangup(phone))
+	if (ipc_phone_hangup(phone, 0))
 		return -1;
 
Index: generic/src/mm/frame.c
===================================================================
--- generic/src/mm/frame.c	(revision 7669bcf004fbab71b35a1a9ec2b476fb2c698b7a)
+++ generic/src/mm/frame.c	(revision eb3d3796fe70e08b188cec351b1979d97243c33f)
@@ -135,4 +135,5 @@
  * Insert-sort zone into zones list
  *
+ * @param newzone New zone to be inserted into zone list
  * @return zone number on success, -1 on error
  */
@@ -173,6 +174,8 @@
  * Try to find a zone where can we find the frame
  *
- * @param hint Start searching in zone 'hint'
- * @param lock Lock zone if true
+ * @param frame Frame number contained in zone
+ * @param pzone If not null, it is used as zone hint. Zone index
+ *              is filled into the variable on success. 
+ * @return Pointer to LOCKED zone containing frame
  *
  * Assume interrupts disable
@@ -221,4 +224,5 @@
  * Assume interrupts are disabled!!
  *
+ * @param order Size (2^order) of free space we are trying to find
  * @param pzone Pointer to preferred zone or NULL, on return contains zone number
  */
@@ -469,4 +473,7 @@
  *
  * Assume zone is locked
+ *
+ * @param zone Pointer to zone from which the frame is to be freed
+ * @param frame_idx Frame index relative to zone
  */
 static void zone_frame_free(zone_t *zone, index_t frame_idx)
@@ -519,4 +526,8 @@
  *
  * Assume z1 & z2 are locked 
+ *
+ * @param z Target zone structure pointer
+ * @param z1 Zone to merge
+ * @param z2 Zone to merge
  */
 
@@ -628,6 +639,7 @@
  *
  * The allocated block need 2^order frames of space. Reduce all frames
- * in block to order 0 and free the unneded frames. This means, that 
- * when freeing the block, you have to free every frame from block.
+ * in block to order 0 and free the unneeded frames. This means, that 
+ * when freeing the previously allocated block starting with frame_idx, 
+ * you have to free every frame.
  *
  * @param zone 
@@ -752,6 +764,6 @@
  *
  * @param start Physical address of the first frame within the zone.
- * @param size Size of the zone. Must be a multiple of FRAME_SIZE.
- * @param conffram Address of configuration frame
+ * @param count Count of frames in zone
+ * @param z Address of configuration information of zone
  * @param flags Zone flags.
  *
@@ -794,5 +806,9 @@
 }
 
-/** Compute configuration data size for zone */
+/** Compute configuration data size for zone
+ *
+ * @param count Size of zone in frames
+ * @return Size of zone configuration info (in bytes)
+ */
 __address zone_conf_size(count_t count)
 {
@@ -807,9 +823,14 @@
 /** Create and add zone to system
  *
- * @param confframe Where configuration frame is supposed to be.
- *                  Always check, that we will not disturb the kernel and possibly init. 
+ * @param start First frame number (absolute)
+ * @param count Size of zone in frames
+ * @param confframe Where configuration frames are supposed to be.
+ *                  Automatically checks, that we will not disturb the 
+ *                  kernel and possibly init. 
  *                  If confframe is given _outside_ this zone, it is expected,
  *                  that the area is already marked BUSY and big enough
- *                  to contain zone_conf_size() amount of data
+ *                  to contain zone_conf_size() amount of data.
+ *                  If the confframe is inside the area, the zone free frame
+ *                  information is modified not to include it.
  *
  * @return Zone number or -1 on error
