Index: uspace/lib/libblock/libblock.c
===================================================================
--- uspace/lib/libblock/libblock.c	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/lib/libblock/libblock.c	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -50,4 +50,5 @@
 #include <adt/list.h>
 #include <adt/hash_table.h>
+#include <macros.h>
 #include <mem.h>
 
@@ -62,5 +63,5 @@
 typedef struct {
 	fibril_mutex_t lock;
-	size_t block_size;		/**< Block size. */
+	size_t lblock_size;		/**< Logical block size. */
 	unsigned block_count;		/**< Total number of blocks. */
 	unsigned blocks_cached;		/**< Number of cached blocks. */
@@ -78,11 +79,12 @@
 	size_t com_size;
 	void *bb_buf;
-	off_t bb_off;
-	size_t bb_size;
+	bn_t bb_addr;
+	size_t pblock_size;		/**< Physical block size. */
 	cache_t *cache;
 } devcon_t;
 
-static int read_block(devcon_t *devcon, bn_t boff, size_t block_size);
-static int write_block(devcon_t *devcon, bn_t boff, size_t block_size);
+static int read_blocks(devcon_t *devcon, bn_t ba, size_t cnt);
+static int write_blocks(devcon_t *devcon, bn_t ba, size_t cnt);
+static size_t get_block_size(int dev_phone, size_t *bsize);
 
 static devcon_t *devcon_search(dev_handle_t dev_handle)
@@ -102,9 +104,12 @@
 }
 
-static int devcon_add(dev_handle_t dev_handle, int dev_phone, void *com_area,
-   size_t com_size)
+static int devcon_add(dev_handle_t dev_handle, int dev_phone, size_t bsize,
+    void *com_area, size_t com_size)
 {
 	link_t *cur;
 	devcon_t *devcon;
+
+	if (com_size < bsize)
+		return EINVAL;
 
 	devcon = malloc(sizeof(devcon_t));
@@ -119,6 +124,6 @@
 	devcon->com_size = com_size;
 	devcon->bb_buf = NULL;
-	devcon->bb_off = 0;
-	devcon->bb_size = 0;
+	devcon->bb_addr = 0;
+	devcon->pblock_size = bsize;
 	devcon->cache = NULL;
 
@@ -149,5 +154,6 @@
 	int dev_phone;
 	void *com_area;
-	
+	size_t bsize;
+
 	com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE,
 	    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
@@ -169,6 +175,12 @@
 		return rc;
 	}
+
+	if (get_block_size(dev_phone, &bsize) != EOK) {
+		munmap(com_area, com_size);
+		ipc_hangup(dev_phone);
+		return rc;
+	}
 	
-	rc = devcon_add(dev_handle, dev_phone, com_area, com_size);
+	rc = devcon_add(dev_handle, dev_phone, bsize, com_area, com_size);
 	if (rc != EOK) {
 		munmap(com_area, com_size);
@@ -201,5 +213,5 @@
 }
 
-int block_bb_read(dev_handle_t dev_handle, off_t off, size_t size)
+int block_bb_read(dev_handle_t dev_handle, bn_t ba)
 {
 	void *bb_buf;
@@ -211,10 +223,10 @@
 	if (devcon->bb_buf)
 		return EEXIST;
-	bb_buf = malloc(size);
+	bb_buf = malloc(devcon->pblock_size);
 	if (!bb_buf)
 		return ENOMEM;
-	
+
 	fibril_mutex_lock(&devcon->com_area_lock);
-	rc = read_block(devcon, 0, size);
+	rc = read_blocks(devcon, 0, 1);
 	if (rc != EOK) {
 		fibril_mutex_unlock(&devcon->com_area_lock);
@@ -222,10 +234,9 @@
 		return rc;
 	}
-	memcpy(bb_buf, devcon->com_area, size);
+	memcpy(bb_buf, devcon->com_area, devcon->pblock_size);
 	fibril_mutex_unlock(&devcon->com_area_lock);
 
 	devcon->bb_buf = bb_buf;
-	devcon->bb_off = off;
-	devcon->bb_size = size;
+	devcon->bb_addr = ba;
 
 	return EOK;
@@ -275,8 +286,11 @@
 	fibril_mutex_initialize(&cache->lock);
 	list_initialize(&cache->free_head);
-	cache->block_size = size;
+	cache->lblock_size = size;
 	cache->block_count = blocks;
 	cache->blocks_cached = 0;
 	cache->mode = mode;
+
+	/* No block size translation a.t.m. */
+	assert(cache->lblock_size == devcon->pblock_size);
 
 	if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
@@ -368,5 +382,5 @@
 			if (!b)
 				goto recycle;
-			b->data = malloc(cache->block_size);
+			b->data = malloc(cache->lblock_size);
 			if (!b->data) {
 				free(b);
@@ -400,6 +414,5 @@
 				fibril_mutex_lock(&devcon->com_area_lock);
 				memcpy(devcon->com_area, b->data, b->size);
-				rc = write_block(devcon, b->boff,
-				    cache->block_size);
+				rc = write_blocks(devcon, b->boff, 1);
 				fibril_mutex_unlock(&devcon->com_area_lock);
 				if (rc != EOK) {
@@ -437,5 +450,5 @@
 		block_initialize(b);
 		b->dev_handle = dev_handle;
-		b->size = cache->block_size;
+		b->size = cache->lblock_size;
 		b->boff = boff;
 		hash_table_insert(&cache->block_hash, &key, &b->hash_link);
@@ -455,6 +468,6 @@
 			 */
 			fibril_mutex_lock(&devcon->com_area_lock);
-			rc = read_block(devcon, b->boff, cache->block_size);
-			memcpy(b->data, devcon->com_area, cache->block_size);
+			rc = read_blocks(devcon, b->boff, 1);
+			memcpy(b->data, devcon->com_area, cache->lblock_size);
 			fibril_mutex_unlock(&devcon->com_area_lock);
 			if (rc != EOK) 
@@ -510,5 +523,5 @@
 		fibril_mutex_lock(&devcon->com_area_lock);
 		memcpy(devcon->com_area, block->data, block->size);
-		rc = write_block(devcon, block->boff, block->size);
+		rc = write_blocks(devcon, block->boff, 1);
 		fibril_mutex_unlock(&devcon->com_area_lock);
 		block->dirty = false;
@@ -588,10 +601,14 @@
  */
 int block_seqread(dev_handle_t dev_handle, off_t *bufpos, size_t *buflen,
-    off_t *pos, void *dst, size_t size, size_t block_size)
+    off_t *pos, void *dst, size_t size)
 {
 	off_t offset = 0;
 	size_t left = size;
-	devcon_t *devcon = devcon_search(dev_handle);
+	size_t block_size;
+	devcon_t *devcon;
+
+	devcon = devcon_search(dev_handle);
 	assert(devcon);
+	block_size = devcon->pblock_size;
 	
 	fibril_mutex_lock(&devcon->com_area_lock);
@@ -620,5 +637,5 @@
 			int rc;
 
-			rc = read_block(devcon, *pos / block_size, block_size);
+			rc = read_blocks(devcon, *pos / block_size, 1);
 			if (rc != EOK) {
 				fibril_mutex_unlock(&devcon->com_area_lock);
@@ -635,25 +652,21 @@
 }
 
-/** Read block from block device.
+/** Read blocks from block device.
  *
  * @param devcon	Device connection.
- * @param boff		Block index.
- * @param block_size	Block size.
+ * @param ba		Address of first block.
+ * @param cnt		Number of blocks.
  * @param src		Buffer for storing the data.
  *
  * @return		EOK on success or negative error code on failure.
  */
-static int read_block(devcon_t *devcon, bn_t boff, size_t block_size)
-{
-	ipcarg_t retval;
+static int read_blocks(devcon_t *devcon, bn_t ba, size_t cnt)
+{
 	int rc;
 
 	assert(devcon);
-	rc = async_req_2_1(devcon->dev_phone, BD_READ_BLOCK, boff, block_size,
-	    &retval);
-	if ((rc != EOK) || (retval != EOK))
-		return (rc != EOK ? rc : (int) retval);
-
-	return EOK;
+	rc = async_req_3_0(devcon->dev_phone, BD_READ_BLOCKS, LOWER32(ba),
+	    UPPER32(ba), cnt);
+	return rc;
 }
 
@@ -661,22 +674,31 @@
  *
  * @param devcon	Device connection.
- * @param boff		Block index.
- * @param block_size	Block size.
+ * @param ba		Address of first block.
+ * @param cnt		Number of blocks.
  * @param src		Buffer containing the data to write.
  *
  * @return		EOK on success or negative error code on failure.
  */
-static int write_block(devcon_t *devcon, bn_t boff, size_t block_size)
-{
-	ipcarg_t retval;
+static int write_blocks(devcon_t *devcon, bn_t ba, size_t cnt)
+{
 	int rc;
 
 	assert(devcon);
-	rc = async_req_2_1(devcon->dev_phone, BD_WRITE_BLOCK, boff, block_size,
-	    &retval);
-	if ((rc != EOK) || (retval != EOK))
-		return (rc != EOK ? rc : (int) retval);
-
-	return EOK;
+	rc = async_req_3_0(devcon->dev_phone, BD_WRITE_BLOCKS, LOWER32(ba),
+	    UPPER32(ba), cnt);
+	return rc;
+}
+
+/** Get block size used by the device. */
+static size_t get_block_size(int dev_phone, size_t *bsize)
+{
+	ipcarg_t bs;
+	int rc;
+
+	rc = async_req_0_1(dev_phone, BD_GET_BLOCK_SIZE, &bs);
+	if (rc == EOK)
+		*bsize = (size_t) bs;
+
+	return rc;
 }
 
Index: uspace/lib/libblock/libblock.h
===================================================================
--- uspace/lib/libblock/libblock.h	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/lib/libblock/libblock.h	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -60,5 +60,5 @@
 #define BLOCK_FLAGS_NOREAD	1
 
-typedef unsigned bn_t;	/**< Block number type. */
+typedef uint64_t bn_t;	/**< Block number type. */
 
 typedef struct block {
@@ -98,5 +98,5 @@
 extern void block_fini(dev_handle_t);
 
-extern int block_bb_read(dev_handle_t, off_t, size_t);
+extern int block_bb_read(dev_handle_t, bn_t);
 extern void *block_bb_get(dev_handle_t);
 
@@ -107,5 +107,5 @@
 
 extern int block_seqread(dev_handle_t, off_t *, size_t *, off_t *, void *,
-    size_t, size_t);
+    size_t);
 
 #endif
Index: uspace/lib/libc/include/ipc/bd.h
===================================================================
--- uspace/lib/libc/include/ipc/bd.h	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/lib/libc/include/ipc/bd.h	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -39,6 +39,7 @@
 
 typedef enum {
-	BD_READ_BLOCK = IPC_FIRST_USER_METHOD,
-	BD_WRITE_BLOCK
+	BD_GET_BLOCK_SIZE = IPC_FIRST_USER_METHOD,
+	BD_READ_BLOCKS,
+	BD_WRITE_BLOCKS
 } bd_request_t;
 
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -62,4 +62,5 @@
 #include <bool.h>
 #include <task.h>
+#include <macros.h>
 
 #include "ata_bd.h"
@@ -86,14 +87,16 @@
 static int ata_bd_init(void);
 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
-static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
+static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
     void *buf);
-static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
+static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
+    const void *buf);
+static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt,
     void *buf);
-static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
+static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     const void *buf);
 static int disk_init(disk_t *d, int disk_id);
 static int drive_identify(int drive_id, void *buf);
 static void disk_print_summary(disk_t *d);
-static int coord_calc(disk_t *d, uint64_t blk_idx, block_coord_t *bc);
+static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
 static void coord_sc_program(const block_coord_t *bc, uint16_t scnt);
 static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
@@ -228,6 +231,6 @@
 	int flags;
 	int retval;
-	off_t idx;
-	size_t size;
+	uint64_t ba;
+	size_t cnt;
 	int disk_id, i;
 
@@ -270,15 +273,27 @@
 			ipc_answer_0(callid, EOK);
 			return;
-		case BD_READ_BLOCK:
-		case BD_WRITE_BLOCK:
-			idx = IPC_GET_ARG1(call);
-			size = IPC_GET_ARG2(call);
-			if (size > comm_size) {
-				retval = EINVAL;
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
 				break;
 			}
-			retval = ata_bd_rdwr(disk_id, method, idx,
-			    size, fs_va);
+			retval = ata_bd_read_blocks(disk_id, ba, cnt, fs_va);
 			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
+				break;
+			}
+			retval = ata_bd_write_blocks(disk_id, ba, cnt, fs_va);
+			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
 		default:
 			retval = EINVAL;
@@ -373,40 +388,37 @@
 }
 
-/** Transfer a logical block from/to the device.
- *
- * @param disk_id	Device index (0 or 1)
- * @param method	@c BD_READ_BLOCK or @c BD_WRITE_BLOCK
- * @param blk_idx	Index of the first block.
- * @param size		Size of the logical block.
- * @param buf		Data buffer.
- *
- * @return EOK on success, EIO on error.
- */
-static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, size_t size,
-    void *buf)
-{
+/** Read multiple blocks from the device. */
+static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
+    void *buf) {
+
 	int rc;
-	size_t now;
-
-	while (size > 0) {
-		now = size < block_size ? size : block_size;
-		if (now != block_size)
-			return EINVAL;
-
-		if (method == BD_READ_BLOCK)
-			rc = ata_bd_read_block(disk_id, blk_idx, 1, buf);
-		else
-			rc = ata_bd_write_block(disk_id, blk_idx, 1, buf);
-
+
+	while (cnt > 0) {
+		rc = ata_bd_read_block(disk_id, ba, 1, buf);
 		if (rc != EOK)
 			return rc;
 
+		++ba;
+		--cnt;
 		buf += block_size;
-		blk_idx++;
-
-		if (size > block_size)
-			size -= block_size;
-		else
-			size = 0;
+	}
+
+	return EOK;
+}
+
+/** Write multiple blocks to the device. */
+static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
+    const void *buf) {
+
+	int rc;
+
+	while (cnt > 0) {
+		rc = ata_bd_write_block(disk_id, ba, 1, buf);
+		if (rc != EOK)
+			return rc;
+
+		++ba;
+		--cnt;
+		buf += block_size;
 	}
 
@@ -466,11 +478,11 @@
  *
  * @param disk_id	Device index (0 or 1)
- * @param blk_idx	Index of the first block.
- * @param blk_cnt	Number of blocks to transfer.
+ * @param ba		Address the first block.
+ * @param cnt		Number of blocks to transfer.
  * @param buf		Buffer for holding the data.
  *
  * @return EOK on success, EIO on error.
  */
-static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
+static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,
     void *buf)
 {
@@ -486,5 +498,5 @@
 
 	/* Compute block coordinates. */
-	if (coord_calc(d, blk_idx, &bc) != EOK)
+	if (coord_calc(d, ba, &bc) != EOK)
 		return EINVAL;
 
@@ -541,11 +553,11 @@
  *
  * @param disk_id	Device index (0 or 1)
- * @param blk_idx	Index of the first block.
- * @param blk_cnt	Number of blocks to transfer.
+ * @param ba		Address of the first block.
+ * @param cnt		Number of blocks to transfer.
  * @param buf		Buffer holding the data to write.
  *
  * @return EOK on success, EIO on error.
  */
-static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
+static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     const void *buf)
 {
@@ -560,5 +572,5 @@
 
 	/* Compute block coordinates. */
-	if (coord_calc(d, blk_idx, &bc) != EOK)
+	if (coord_calc(d, ba, &bc) != EOK)
 		return EINVAL;
 
@@ -620,5 +632,5 @@
  * @return EOK on success or EINVAL if block index is past end of device.
  */
-static int coord_calc(disk_t *d, uint64_t blk_idx, block_coord_t *bc)
+static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc)
 {
 	uint64_t c;
@@ -626,5 +638,5 @@
 
 	/* Check device bounds. */
-	if (blk_idx >= d->blocks)
+	if (ba >= d->blocks)
 		return EINVAL;
 
@@ -634,6 +646,6 @@
 	case am_chs:
 		/* Compute CHS coordinates. */
-		c = blk_idx / (d->geom.heads * d->geom.sectors);
-		idx = blk_idx % (d->geom.heads * d->geom.sectors);
+		c = ba / (d->geom.heads * d->geom.sectors);
+		idx = ba % (d->geom.heads * d->geom.sectors);
 
 		bc->cyl_lo = c & 0xff;
@@ -645,18 +657,18 @@
 	case am_lba28:
 		/* Compute LBA-28 coordinates. */
-		bc->c0 = blk_idx & 0xff;		/* bits 0-7 */
-		bc->c1 = (blk_idx >> 8) & 0xff;		/* bits 8-15 */
-		bc->c2 = (blk_idx >> 16) & 0xff;	/* bits 16-23 */
-		bc->h  = (blk_idx >> 24) & 0x0f;	/* bits 24-27 */
+		bc->c0 = ba & 0xff;		/* bits 0-7 */
+		bc->c1 = (ba >> 8) & 0xff;	/* bits 8-15 */
+		bc->c2 = (ba >> 16) & 0xff;	/* bits 16-23 */
+		bc->h  = (ba >> 24) & 0x0f;	/* bits 24-27 */
 		break;
 
 	case am_lba48:
 		/* Compute LBA-48 coordinates. */
-		bc->c0 = blk_idx & 0xff;		/* bits 0-7 */
-		bc->c1 = (blk_idx >> 8) & 0xff;		/* bits 8-15 */
-		bc->c2 = (blk_idx >> 16) & 0xff;	/* bits 16-23 */
-		bc->c3 = (blk_idx >> 24) & 0xff;	/* bits 24-31 */
-		bc->c4 = (blk_idx >> 32) & 0xff;	/* bits 32-39 */
-		bc->c5 = (blk_idx >> 40) & 0xff;	/* bits 40-47 */
+		bc->c0 = ba & 0xff;		/* bits 0-7 */
+		bc->c1 = (ba >> 8) & 0xff;	/* bits 8-15 */
+		bc->c2 = (ba >> 16) & 0xff;	/* bits 16-23 */
+		bc->c3 = (ba >> 24) & 0xff;	/* bits 24-31 */
+		bc->c4 = (ba >> 32) & 0xff;	/* bits 32-39 */
+		bc->c5 = (ba >> 40) & 0xff;	/* bits 40-47 */
 		bc->h  = 0;
 		break;
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -51,8 +51,9 @@
 #include <bool.h>
 #include <task.h>
+#include <macros.h>
 
 #define NAME "file_bd"
 
-static size_t comm_size;
+static const size_t block_size = 512;
 static FILE *img;
 
@@ -62,6 +63,6 @@
 static int file_bd_init(const char *fname);
 static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
-static int file_bd_read(off_t blk_idx, size_t size, void *buf);
-static int file_bd_write(off_t blk_idx, size_t size, void *buf);
+static int file_bd_read_blocks(uint64_t ba, size_t cnt, void *buf);
+static int file_bd_write_blocks(uint64_t ba, size_t cnt, const void *buf);
 
 int main(int argc, char **argv)
@@ -120,8 +121,9 @@
 	ipc_call_t call;
 	ipcarg_t method;
+	size_t comm_size;
 	int flags;
 	int retval;
-	off_t idx;
-	size_t size;
+	uint64_t ba;
+	size_t cnt;
 
 	/* Answer the IPC_M_CONNECT_ME_TO call. */
@@ -149,17 +151,27 @@
 			ipc_answer_0(callid, EOK);
 			return;
-		case BD_READ_BLOCK:
-		case BD_WRITE_BLOCK:
-			idx = IPC_GET_ARG1(call);
-			size = IPC_GET_ARG2(call);
-			if (size > comm_size) {
-				retval = EINVAL;
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
 				break;
 			}
-			if (method == BD_READ_BLOCK)
-				retval = file_bd_read(idx, size, fs_va);
-			else
-				retval = file_bd_write(idx, size, fs_va);
+			retval = file_bd_read_blocks(ba, cnt, fs_va);
 			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
+				break;
+			}
+			retval = file_bd_write_blocks(ba, cnt, fs_va);
+			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
 		default:
 			retval = EINVAL;
@@ -170,5 +182,6 @@
 }
 
-static int file_bd_read(off_t blk_idx, size_t size, void *buf)
+/** Read blocks from the device. */
+static int file_bd_read_blocks(uint64_t ba, size_t cnt, void *buf)
 {
 	size_t n_rd;
@@ -176,6 +189,6 @@
 	fibril_mutex_lock(&dev_lock);
 
-	fseek(img, blk_idx * size, SEEK_SET);
-	n_rd = fread(buf, 1, size, img);
+	fseek(img, ba * block_size, SEEK_SET);
+	n_rd = fread(buf, block_size, cnt, img);
 
 	if (ferror(img)) {
@@ -186,11 +199,12 @@
 	fibril_mutex_unlock(&dev_lock);
 
-	if (n_rd < size) 
-		return EINVAL;	/* Read beyond end of disk */
+	if (n_rd < cnt)
+		return EINVAL;	/* Read beyond end of device */
 
 	return EOK;
 }
 
-static int file_bd_write(off_t blk_idx, size_t size, void *buf)
+/** Write blocks to the device. */
+static int file_bd_write_blocks(uint64_t ba, size_t cnt, const void *buf)
 {
 	size_t n_wr;
@@ -198,8 +212,8 @@
 	fibril_mutex_lock(&dev_lock);
 
-	fseek(img, blk_idx * size, SEEK_SET);
-	n_wr = fread(buf, 1, size, img);
-
-	if (ferror(img) || n_wr < size) {
+	fseek(img, ba * block_size, SEEK_SET);
+	n_wr = fread(buf, block_size, cnt, img);
+
+	if (ferror(img) || n_wr < cnt) {
 		fibril_mutex_unlock(&dev_lock);
 		return EIO;	/* Write error */
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -47,4 +47,5 @@
 #include <sys/types.h>
 #include <errno.h>
+#include <macros.h>
 #include <task.h>
 
@@ -97,10 +98,10 @@
 static int gxe_bd_init(void);
 static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
-static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
+static int gxe_bd_read_blocks(int disk_id, uint64_t ba, unsigned cnt,
     void *buf);
-static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size,
-    void *buf);
-static int gxe_bd_write_block(int disk_id, uint64_t offset, size_t size,
+static int gxe_bd_write_blocks(int disk_id, uint64_t ba, unsigned cnt,
     const void *buf);
+static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf);
+static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf);
 
 int main(int argc, char **argv)
@@ -163,6 +164,6 @@
 	int flags;
 	int retval;
-	off_t idx;
-	size_t size;
+	uint64_t ba;
+	unsigned cnt;
 	int disk_id, i;
 
@@ -185,4 +186,9 @@
 
 	if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
+		ipc_answer_0(callid, EHANGUP);
+		return;
+	}
+
+	if (comm_size < block_size) {
 		ipc_answer_0(callid, EHANGUP);
 		return;
@@ -205,15 +211,27 @@
 			ipc_answer_0(callid, EOK);
 			return;
-		case BD_READ_BLOCK:
-		case BD_WRITE_BLOCK:
-			idx = IPC_GET_ARG1(call);
-			size = IPC_GET_ARG2(call);
-			if (size > comm_size) {
-				retval = EINVAL;
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
 				break;
 			}
-			retval = gx_bd_rdwr(disk_id, method, idx * size,
-			    size, fs_va);
+			retval = gxe_bd_read_blocks(disk_id, ba, cnt, fs_va);
 			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
+				break;
+			}
+			retval = gxe_bd_write_blocks(disk_id, ba, cnt, fs_va);
+			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
 		default:
 			retval = EINVAL;
@@ -224,43 +242,55 @@
 }
 
-static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
-    void *buf)
-{
+/** Read multiple blocks from the device. */
+static int gxe_bd_read_blocks(int disk_id, uint64_t ba, unsigned cnt,
+    void *buf) {
+
 	int rc;
-	size_t now;
-
-	while (size > 0) {
-		now = size < block_size ? size : block_size;
-
-		if (method == BD_READ_BLOCK)
-			rc = gxe_bd_read_block(disk_id, offset, now, buf);
-		else
-			rc = gxe_bd_write_block(disk_id, offset, now, buf);
-
+
+	while (cnt > 0) {
+		rc = gxe_bd_read_block(disk_id, ba, buf);
 		if (rc != EOK)
 			return rc;
 
+		++ba;
+		--cnt;
 		buf += block_size;
-		offset += block_size;
-
-		if (size > block_size)
-			size -= block_size;
-		else
-			size = 0;
-	}
-
-	return EOK;
-}
-
-static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size,
-    void *buf)
+	}
+
+	return EOK;
+}
+
+/** Write multiple blocks to the device. */
+static int gxe_bd_write_blocks(int disk_id, uint64_t ba, unsigned cnt,
+    const void *buf) {
+
+	int rc;
+
+	while (cnt > 0) {
+		rc = gxe_bd_write_block(disk_id, ba, buf);
+		if (rc != EOK)
+			return rc;
+
+		++ba;
+		--cnt;
+		buf += block_size;
+	}
+
+	return EOK;
+}
+
+/** Read a block from the device. */
+static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf)
 {
 	uint32_t status;
+	uint64_t byte_addr;
 	size_t i;
 	uint32_t w;
 
+	byte_addr = ba * block_size;
+
 	fibril_mutex_lock(&dev_lock[disk_id]);
-	pio_write_32(&dev->offset_lo, (uint32_t) offset);
-	pio_write_32(&dev->offset_hi, offset >> 32);
+	pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
+	pio_write_32(&dev->offset_hi, byte_addr >> 32);
 	pio_write_32(&dev->disk_id, disk_id);
 	pio_write_32(&dev->control, CTL_READ_START);
@@ -272,5 +302,5 @@
 	}
 
-	for (i = 0; i < size; i++) {
+	for (i = 0; i < block_size; i++) {
 		((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]);
 	}
@@ -280,17 +310,21 @@
 }
 
-static int gxe_bd_write_block(int disk_id, uint64_t offset, size_t size,
-    const void *buf)
+/** Write a block to the device. */
+static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf)
 {
 	uint32_t status;
+	uint64_t byte_addr;
 	size_t i;
 
-	for (i = 0; i < size; i++) {
+	byte_addr = ba * block_size;
+
+	fibril_mutex_lock(&dev_lock[disk_id]);
+
+	for (i = 0; i < block_size; i++) {
 		pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]);
 	}
 
-	fibril_mutex_lock(&dev_lock[disk_id]);
-	pio_write_32(&dev->offset_lo, (uint32_t) offset);
-	pio_write_32(&dev->offset_hi, offset >> 32);
+	pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
+	pio_write_32(&dev->offset_hi, byte_addr >> 32);
 	pio_write_32(&dev->disk_id, disk_id);
 	pio_write_32(&dev->control, CTL_WRITE_START);
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/srv/bd/rd/rd.c	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -55,11 +55,18 @@
 #include <devmap.h>
 #include <ipc/bd.h>
+#include <macros.h>
 
 #define NAME "rd"
 
-/** Pointer to the ramdisk's image. */
+/** Pointer to the ramdisk's image */
 static void *rd_addr;
-/** Size of the ramdisk. */
+/** Size of the ramdisk */
 static size_t rd_size;
+
+/** Block size */
+static const size_t block_size = 512;
+
+static int rd_read_blocks(uint64_t ba, size_t cnt, void *buf);
+static int rd_write_blocks(uint64_t ba, size_t cnt, const void *buf);
 
 /**
@@ -82,7 +89,7 @@
 	int retval;
 	void *fs_va = NULL;
-	off_t offset;
-	size_t block_size;
-	size_t maxblock_size;
+	uint64_t ba;
+	size_t cnt;
+	size_t comm_size;
 
 	/*
@@ -95,6 +102,6 @@
 	 */
 	int flags;
-	if (ipc_share_out_receive(&callid, &maxblock_size, &flags)) {
-		fs_va = as_get_mappable_page(maxblock_size);
+	if (ipc_share_out_receive(&callid, &comm_size, &flags)) {
+		fs_va = as_get_mappable_page(comm_size);
 		if (fs_va) {
 			(void) ipc_share_out_finalize(callid, fs_va);
@@ -123,48 +130,27 @@
 			ipc_answer_0(callid, EOK);
 			return;
-		case BD_READ_BLOCK:
-			offset = IPC_GET_ARG1(call);
-			block_size = IPC_GET_ARG2(call);
-			if (block_size > maxblock_size) {
-				/*
-				 * Maximum block size exceeded.
-				 */
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
 				retval = ELIMIT;
 				break;
 			}
-			if (offset * block_size > rd_size - block_size) {
-				/*
-				 * Reading past the end of the device.
-				 */
+			retval = rd_read_blocks(ba, cnt, fs_va);
+			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
 				retval = ELIMIT;
 				break;
 			}
-			fibril_rwlock_read_lock(&rd_lock);
-			memcpy(fs_va, rd_addr + offset * block_size, block_size);
-			fibril_rwlock_read_unlock(&rd_lock);
-			retval = EOK;
+			retval = rd_write_blocks(ba, cnt, fs_va);
 			break;
-		case BD_WRITE_BLOCK:
-			offset = IPC_GET_ARG1(call);
-			block_size = IPC_GET_ARG2(call);
-			if (block_size > maxblock_size) {
-				/*
-				 * Maximum block size exceeded.
-				 */
-				retval = ELIMIT;
-				break;
-			}
-			if (offset * block_size > rd_size - block_size) {
-				/*
-				 * Writing past the end of the device.
-				 */
-				retval = ELIMIT;
-				break;
-			}
-			fibril_rwlock_write_lock(&rd_lock);
-			memcpy(rd_addr + offset * block_size, fs_va, block_size);
-			fibril_rwlock_write_unlock(&rd_lock);
-			retval = EOK;
-			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
 		default:
 			/*
@@ -181,4 +167,34 @@
 }
 
+/** Read blocks from the device. */
+static int rd_read_blocks(uint64_t ba, size_t cnt, void *buf)
+{
+	if ((ba + cnt) * block_size > rd_size) {
+		/* Reading past the end of the device. */
+		return ELIMIT;
+	}
+
+	fibril_rwlock_read_lock(&rd_lock);
+	memcpy(buf, rd_addr + ba * block_size, block_size * cnt);
+	fibril_rwlock_read_unlock(&rd_lock);
+
+	return EOK;
+}
+
+/** Write blocks to the device. */
+static int rd_write_blocks(uint64_t ba, size_t cnt, const void *buf)
+{
+	if ((ba + cnt) * block_size > rd_size) {
+		/* Writing past the end of the device. */
+		return ELIMIT;
+	}
+
+	fibril_rwlock_write_lock(&rd_lock);
+	memcpy(rd_addr + ba * block_size, buf, block_size * cnt);
+	fibril_rwlock_write_unlock(&rd_lock);
+
+	return EOK;
+}
+
 /** Prepare the ramdisk image for operation. */
 static bool rd_init(void)
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -818,5 +818,5 @@
 
 	/* prepare the boot block */
-	rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
+	rc = block_bb_read(dev_handle, BS_BLOCK);
 	if (rc != EOK) {
 		block_fini(dev_handle);
Index: uspace/srv/fs/tmpfs/tmpfs_dump.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision ff62c6d0bdc03c5f2a281a6fe8a6a8771b20b846)
+++ uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 1ee00b7af6412235d0d33719a2a5c82edac587e8)
@@ -47,5 +47,5 @@
 #include <byteorder.h>
 
-#define TMPFS_BLOCK_SIZE	1024
+#define TMPFS_COMM_SIZE		1024
 
 struct rdentry {
@@ -69,5 +69,5 @@
 		
 		if (block_seqread(dev, bufpos, buflen, pos, &entry,
-		    sizeof(entry), TMPFS_BLOCK_SIZE) != EOK)
+		    sizeof(entry)) != EOK)
 			return false;
 		
@@ -89,5 +89,5 @@
 			
 			if (block_seqread(dev, bufpos, buflen, pos, fname,
-			    entry.len, TMPFS_BLOCK_SIZE) != EOK) {
+			    entry.len) != EOK) {
 				ops->destroy(fn);
 				free(fname);
@@ -105,5 +105,5 @@
 			
 			if (block_seqread(dev, bufpos, buflen, pos, &size,
-			    sizeof(size), TMPFS_BLOCK_SIZE) != EOK)
+			    sizeof(size)) != EOK)
 				return false;
 			
@@ -117,5 +117,5 @@
 			nodep->size = size;
 			if (block_seqread(dev, bufpos, buflen, pos, nodep->data,
-			    size, TMPFS_BLOCK_SIZE) != EOK)
+			    size) != EOK)
 				return false;
 			
@@ -133,5 +133,5 @@
 			
 			if (block_seqread(dev, bufpos, buflen, pos, fname,
-			    entry.len, TMPFS_BLOCK_SIZE) != EOK) {
+			    entry.len) != EOK) {
 				ops->destroy(fn);
 				free(fname);
@@ -166,5 +166,5 @@
 	int rc;
 
-	rc = block_init(dev, TMPFS_BLOCK_SIZE);
+	rc = block_init(dev, TMPFS_COMM_SIZE);
 	if (rc != EOK)
 		return false; 
@@ -175,6 +175,5 @@
 	
 	char tag[6];
-	if (block_seqread(dev, &bufpos, &buflen, &pos, tag, 5,
-	    TMPFS_BLOCK_SIZE) != EOK)
+	if (block_seqread(dev, &bufpos, &buflen, &pos, tag, 5) != EOK)
 		goto error;
 	
