Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/block/libblock.c	(revision 867e25550ec16ab37e83e9c9b8e5a40fec8e6d55)
@@ -2,4 +2,5 @@
  * Copyright (c) 2008 Jakub Jermar
  * Copyright (c) 2008 Martin Decky
+ * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
  *
@@ -51,4 +52,6 @@
 #include <macros.h>
 #include <mem.h>
+#include <malloc.h>
+#include <stdio.h>
 #include <sys/typefmt.h>
 #include <stacktrace.h>
@@ -57,17 +60,17 @@
 static FIBRIL_MUTEX_INITIALIZE(dcl_lock);
 /** Device connection list head. */
-static LIST_INITIALIZE(dcl_head);
-
-#define CACHE_BUCKETS_LOG2		10
-#define CACHE_BUCKETS			(1 << CACHE_BUCKETS_LOG2)
+static LIST_INITIALIZE(dcl);
+
+#define CACHE_BUCKETS_LOG2  10
+#define CACHE_BUCKETS       (1 << CACHE_BUCKETS_LOG2)
 
 typedef struct {
 	fibril_mutex_t lock;
-	size_t lblock_size;		/**< Logical block size. */
-	unsigned blocks_cluster;	/**< Physical blocks per block_t */
-	unsigned block_count;		/**< Total number of blocks. */
-	unsigned blocks_cached;		/**< Number of cached blocks. */
+	size_t lblock_size;       /**< Logical block size. */
+	unsigned blocks_cluster;  /**< Physical blocks per block_t */
+	unsigned block_count;     /**< Total number of blocks. */
+	unsigned blocks_cached;   /**< Number of cached blocks. */
 	hash_table_t block_hash;
-	link_t free_head;
+	list_t free_list;
 	enum cache_mode mode;
 } cache_t;
@@ -76,5 +79,5 @@
 	link_t link;
 	devmap_handle_t devmap_handle;
-	int dev_phone;
+	async_sess_t *sess;
 	fibril_mutex_t comm_area_lock;
 	void *comm_area;
@@ -82,20 +85,19 @@
 	void *bb_buf;
 	aoff64_t bb_addr;
-	size_t pblock_size;		/**< Physical block size. */
+	size_t pblock_size;  /**< Physical block size. */
 	cache_t *cache;
 } devcon_t;
 
-static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt);
-static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt);
-static int get_block_size(int dev_phone, size_t *bsize);
-static int get_num_blocks(int dev_phone, aoff64_t *nblocks);
-static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba);
+static int read_blocks(devcon_t *, aoff64_t, size_t);
+static int write_blocks(devcon_t *, aoff64_t, size_t);
+static int get_block_size(async_sess_t *, size_t *);
+static int get_num_blocks(async_sess_t *, aoff64_t *);
+static aoff64_t ba_ltop(devcon_t *, aoff64_t);
 
 static devcon_t *devcon_search(devmap_handle_t devmap_handle)
 {
-	link_t *cur;
-
 	fibril_mutex_lock(&dcl_lock);
-	for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
+	
+	list_foreach(dcl, cur) {
 		devcon_t *devcon = list_get_instance(cur, devcon_t, link);
 		if (devcon->devmap_handle == devmap_handle) {
@@ -104,17 +106,17 @@
 		}
 	}
+	
 	fibril_mutex_unlock(&dcl_lock);
 	return NULL;
 }
 
-static int devcon_add(devmap_handle_t devmap_handle, int dev_phone, size_t bsize,
-    void *comm_area, size_t comm_size)
-{
-	link_t *cur;
+static int devcon_add(devmap_handle_t devmap_handle, async_sess_t *sess,
+    size_t bsize, void *comm_area, size_t comm_size)
+{
 	devcon_t *devcon;
-
+	
 	if (comm_size < bsize)
 		return EINVAL;
-
+	
 	devcon = malloc(sizeof(devcon_t));
 	if (!devcon)
@@ -123,5 +125,5 @@
 	link_initialize(&devcon->link);
 	devcon->devmap_handle = devmap_handle;
-	devcon->dev_phone = dev_phone;
+	devcon->sess = sess;
 	fibril_mutex_initialize(&devcon->comm_area_lock);
 	devcon->comm_area = comm_area;
@@ -131,7 +133,7 @@
 	devcon->pblock_size = bsize;
 	devcon->cache = NULL;
-
+	
 	fibril_mutex_lock(&dcl_lock);
-	for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
+	list_foreach(dcl, cur) {
 		devcon_t *d = list_get_instance(cur, devcon_t, link);
 		if (d->devmap_handle == devmap_handle) {
@@ -141,5 +143,5 @@
 		}
 	}
-	list_append(&devcon->link, &dcl_head);
+	list_append(&devcon->link, &dcl);
 	fibril_mutex_unlock(&dcl_lock);
 	return EOK;
@@ -153,44 +155,46 @@
 }
 
-int block_init(devmap_handle_t devmap_handle, size_t comm_size)
-{
-	int rc;
-	int dev_phone;
-	void *comm_area;
-	size_t bsize;
-
-	comm_area = mmap(NULL, comm_size, PROTO_READ | PROTO_WRITE,
+int block_init(exch_mgmt_t mgmt, devmap_handle_t devmap_handle,
+    size_t comm_size)
+{
+	void *comm_area = mmap(NULL, comm_size, PROTO_READ | PROTO_WRITE,
 	    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
-	if (!comm_area) {
+	if (!comm_area)
 		return ENOMEM;
-	}
-
-	dev_phone = devmap_device_connect(devmap_handle, IPC_FLAG_BLOCKING);
-	if (dev_phone < 0) {
+	
+	async_sess_t *sess = devmap_device_connect(mgmt, devmap_handle,
+	    IPC_FLAG_BLOCKING);
+	if (!sess) {
 		munmap(comm_area, comm_size);
-		return dev_phone;
-	}
-
-	rc = async_share_out_start(dev_phone, comm_area,
+		return ENOENT;
+	}
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_share_out_start(exch, comm_area,
 	    AS_AREA_READ | AS_AREA_WRITE);
-	if (rc != EOK) {
-	    	munmap(comm_area, comm_size);
-		async_hangup(dev_phone);
-		return rc;
-	}
-
-	if (get_block_size(dev_phone, &bsize) != EOK) {
-		munmap(comm_area, comm_size);
-		async_hangup(dev_phone);
-		return rc;
-	}
-	
-	rc = devcon_add(devmap_handle, dev_phone, bsize, comm_area, comm_size);
+	async_exchange_end(exch);
+	
 	if (rc != EOK) {
 		munmap(comm_area, comm_size);
-		async_hangup(dev_phone);
+		async_hangup(sess);
 		return rc;
 	}
-
+	
+	size_t bsize;
+	rc = get_block_size(sess, &bsize);
+	
+	if (rc != EOK) {
+		munmap(comm_area, comm_size);
+		async_hangup(sess);
+		return rc;
+	}
+	
+	rc = devcon_add(devmap_handle, sess, bsize, comm_area, comm_size);
+	if (rc != EOK) {
+		munmap(comm_area, comm_size);
+		async_hangup(sess);
+		return rc;
+	}
+	
 	return EOK;
 }
@@ -203,14 +207,14 @@
 	if (devcon->cache)
 		(void) block_cache_fini(devmap_handle);
-
+	
 	devcon_remove(devcon);
-
+	
 	if (devcon->bb_buf)
 		free(devcon->bb_buf);
-
+	
 	munmap(devcon->comm_area, devcon->comm_size);
-	async_hangup(devcon->dev_phone);
-
-	free(devcon);	
+	async_hangup(devcon->sess);
+	
+	free(devcon);
 }
 
@@ -254,5 +258,5 @@
 static hash_index_t cache_hash(unsigned long *key)
 {
-	return *key & (CACHE_BUCKETS - 1);
+	return MERGE_LOUP32(key[0], key[1]) & (CACHE_BUCKETS - 1);
 }
 
@@ -260,5 +264,5 @@
 {
 	block_t *b = hash_table_get_instance(item, block_t, hash_link);
-	return b->lba == *key;
+	return b->lba == MERGE_LOUP32(key[0], key[1]);
 }
 
@@ -287,5 +291,5 @@
 	
 	fibril_mutex_initialize(&cache->lock);
-	list_initialize(&cache->free_head);
+	list_initialize(&cache->free_list);
 	cache->lblock_size = size;
 	cache->block_count = blocks;
@@ -301,5 +305,5 @@
 	cache->blocks_cluster = cache->lblock_size / devcon->pblock_size;
 
-	if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
+	if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 2,
 	    &cache_ops)) {
 		free(cache);
@@ -328,6 +332,6 @@
 	 * bother with the cache and block locks because we are single-threaded.
 	 */
-	while (!list_empty(&cache->free_head)) {
-		block_t *b = list_get_instance(cache->free_head.next,
+	while (!list_empty(&cache->free_list)) {
+		block_t *b = list_get_instance(list_first(&cache->free_list),
 		    block_t, free_link);
 
@@ -340,6 +344,9 @@
 		}
 
-		unsigned long key = b->lba;
-		hash_table_remove(&cache->block_hash, &key, 1);
+		unsigned long key[2] = {
+			LOWER32(b->lba),
+			UPPER32(b->lba)
+		};
+		hash_table_remove(&cache->block_hash, key, 2);
 		
 		free(b->data);
@@ -360,5 +367,5 @@
 	if (cache->blocks_cached < CACHE_LO_WATERMARK)
 		return true;
-	if (!list_empty(&cache->free_head))
+	if (!list_empty(&cache->free_list))
 		return false;
 	return true;
@@ -394,5 +401,9 @@
 	block_t *b;
 	link_t *l;
-	unsigned long key = ba;
+	unsigned long key[2] = {
+		LOWER32(ba),
+		UPPER32(ba)
+	};
+
 	int rc;
 	
@@ -409,5 +420,5 @@
 
 	fibril_mutex_lock(&cache->lock);
-	l = hash_table_find(&cache->block_hash, &key);
+	l = hash_table_find(&cache->block_hash, key);
 	if (l) {
 found:
@@ -447,12 +458,11 @@
 			 * Try to recycle a block from the free list.
 			 */
-			unsigned long temp_key;
 recycle:
-			if (list_empty(&cache->free_head)) {
+			if (list_empty(&cache->free_list)) {
 				fibril_mutex_unlock(&cache->lock);
 				rc = ENOMEM;
 				goto out;
 			}
-			l = cache->free_head.next;
+			l = list_first(&cache->free_list);
 			b = list_get_instance(l, block_t, free_link);
 
@@ -469,5 +479,5 @@
 				 */
 				list_remove(&b->free_link);
-				list_append(&b->free_link, &cache->free_head);
+				list_append(&b->free_link, &cache->free_list);
 				fibril_mutex_unlock(&cache->lock);
 				fibril_mutex_lock(&devcon->comm_area_lock);
@@ -495,5 +505,5 @@
 					goto retry;
 				}
-				l = hash_table_find(&cache->block_hash, &key);
+				l = hash_table_find(&cache->block_hash, key);
 				if (l) {
 					/*
@@ -518,6 +528,9 @@
 			 */
 			list_remove(&b->free_link);
-			temp_key = b->lba;
-			hash_table_remove(&cache->block_hash, &temp_key, 1);
+			unsigned long temp_key[2] = {
+				LOWER32(b->lba),
+				UPPER32(b->lba)
+			};
+			hash_table_remove(&cache->block_hash, temp_key, 2);
 		}
 
@@ -527,5 +540,5 @@
 		b->lba = ba;
 		b->pba = ba_ltop(devcon, b->lba);
-		hash_table_insert(&cache->block_hash, &key, &b->hash_link);
+		hash_table_insert(&cache->block_hash, key, &b->hash_link);
 
 		/*
@@ -639,6 +652,9 @@
 			 * Take the block out of the cache and free it.
 			 */
-			unsigned long key = block->lba;
-			hash_table_remove(&cache->block_hash, &key, 1);
+			unsigned long key[2] = {
+				LOWER32(block->lba),
+				UPPER32(block->lba)
+			};
+			hash_table_remove(&cache->block_hash, key, 2);
 			fibril_mutex_unlock(&block->lock);
 			free(block->data);
@@ -661,5 +677,5 @@
 			goto retry;
 		}
-		list_append(&block->free_link, &cache->free_head);
+		list_append(&block->free_link, &cache->free_list);
 	}
 	fibril_mutex_unlock(&block->lock);
@@ -805,5 +821,5 @@
 	assert(devcon);
 	
-	return get_block_size(devcon->dev_phone, bsize);
+	return get_block_size(devcon->sess, bsize);
 }
 
@@ -817,10 +833,60 @@
 int block_get_nblocks(devmap_handle_t devmap_handle, aoff64_t *nblocks)
 {
-	devcon_t *devcon;
-
-	devcon = devcon_search(devmap_handle);
-	assert(devcon);
-	
-	return get_num_blocks(devcon->dev_phone, nblocks);
+	devcon_t *devcon = devcon_search(devmap_handle);
+	assert(devcon);
+	
+	return get_num_blocks(devcon->sess, nblocks);
+}
+
+/** Read bytes directly from the device (bypass cache)
+ * 
+ * @param devmap_handle	Device handle of the block device.
+ * @param abs_offset	Absolute offset in bytes where to start reading
+ * @param bytes			Number of bytes to read
+ * @param data			Buffer that receives the data
+ * 
+ * @return		EOK on success or negative error code on failure.
+ */
+int block_read_bytes_direct(devmap_handle_t devmap_handle, aoff64_t abs_offset,
+    size_t bytes, void *data)
+{
+	int rc;
+	size_t phys_block_size;
+	size_t buf_size;
+	void *buffer;
+	aoff64_t first_block;
+	aoff64_t last_block;
+	size_t blocks;
+	size_t offset;
+	
+	rc = block_get_bsize(devmap_handle, &phys_block_size);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	/* calculate data position and required space */
+	first_block = abs_offset / phys_block_size;
+	offset = abs_offset % phys_block_size;
+	last_block = (abs_offset + bytes - 1) / phys_block_size;
+	blocks = last_block - first_block + 1;
+	buf_size = blocks * phys_block_size;
+	
+	/* read the data into memory */
+	buffer = malloc(buf_size);
+	if (buffer == NULL) {
+		return ENOMEM;
+	}
+	
+	rc = block_read_direct(devmap_handle, first_block, blocks, buffer);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+	
+	/* copy the data from the buffer */
+	memcpy(data, buffer + offset, bytes);
+	free(buffer);
+	
+	return EOK;
 }
 
@@ -836,9 +902,11 @@
 static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt)
 {
-	int rc;
-
-	assert(devcon);
-	rc = async_req_3_0(devcon->dev_phone, BD_READ_BLOCKS, LOWER32(ba),
+	assert(devcon);
+	
+	async_exch_t *exch = async_exchange_begin(devcon->sess);
+	int rc = async_req_3_0(exch, BD_READ_BLOCKS, LOWER32(ba),
 	    UPPER32(ba), cnt);
+	async_exchange_end(exch);
+	
 	if (rc != EOK) {
 		printf("Error %d reading %zu blocks starting at block %" PRIuOFF64
@@ -849,4 +917,5 @@
 #endif
 	}
+	
 	return rc;
 }
@@ -863,9 +932,11 @@
 static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt)
 {
-	int rc;
-
-	assert(devcon);
-	rc = async_req_3_0(devcon->dev_phone, BD_WRITE_BLOCKS, LOWER32(ba),
+	assert(devcon);
+	
+	async_exch_t *exch = async_exchange_begin(devcon->sess);
+	int rc = async_req_3_0(exch, BD_WRITE_BLOCKS, LOWER32(ba),
 	    UPPER32(ba), cnt);
+	async_exchange_end(exch);
+	
 	if (rc != EOK) {
 		printf("Error %d writing %zu blocks starting at block %" PRIuOFF64
@@ -875,31 +946,36 @@
 #endif
 	}
+	
 	return rc;
 }
 
 /** Get block size used by the device. */
-static int get_block_size(int dev_phone, size_t *bsize)
+static int get_block_size(async_sess_t *sess, size_t *bsize)
 {
 	sysarg_t bs;
-	int rc;
-
-	rc = async_req_0_1(dev_phone, BD_GET_BLOCK_SIZE, &bs);
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_0_1(exch, BD_GET_BLOCK_SIZE, &bs);
+	async_exchange_end(exch);
+	
 	if (rc == EOK)
 		*bsize = (size_t) bs;
-
+	
 	return rc;
 }
 
 /** Get total number of blocks on block device. */
-static int get_num_blocks(int dev_phone, aoff64_t *nblocks)
-{
-	sysarg_t nb_l, nb_h;
-	int rc;
-
-	rc = async_req_0_2(dev_phone, BD_GET_NUM_BLOCKS, &nb_l, &nb_h);
-	if (rc == EOK) {
+static int get_num_blocks(async_sess_t *sess, aoff64_t *nblocks)
+{
+	sysarg_t nb_l;
+	sysarg_t nb_h;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_0_2(exch, BD_GET_NUM_BLOCKS, &nb_l, &nb_h);
+	async_exchange_end(exch);
+	
+	if (rc == EOK)
 		*nblocks = (aoff64_t) MERGE_LOUP32(nb_l, nb_h);
-	}
-
+	
 	return rc;
 }
