Index: uspace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -37,5 +37,5 @@
 #include <as.h>
 #include <async.h>
-#include <ipc/bd.h>
+#include <bd_srv.h>
 #include <macros.h>
 #include <usb/dev/driver.h>
@@ -82,4 +82,25 @@
     void *arg);
 
+static int usbmast_bd_open(bd_srv_t *);
+static int usbmast_bd_close(bd_srv_t *);
+static int usbmast_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+static int usbmast_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+static int usbmast_bd_get_block_size(bd_srv_t *, size_t *);
+static int usbmast_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
+
+static bd_ops_t usbmast_bd_ops = {
+	.open = usbmast_bd_open,
+	.close = usbmast_bd_close,
+	.read_blocks = usbmast_bd_read_blocks,
+	.write_blocks = usbmast_bd_write_blocks,
+	.get_block_size = usbmast_bd_get_block_size,
+	.get_num_blocks = usbmast_bd_get_num_blocks
+};
+
+static usbmast_fun_t *bd_srv_usbmast(bd_srv_t *bd)
+{
+	return (usbmast_fun_t *)bd->arg;
+}
+
 /** Callback when a device is removed from the system.
  *
@@ -219,4 +240,8 @@
 	mfun->lun = lun;
 
+	bd_srv_init(&mfun->bd);
+	mfun->bd.ops = &usbmast_bd_ops;
+	mfun->bd.arg = mfun;
+
 	/* Set up a connection handler. */
 	fun->conn_handler = usbmast_bd_connection;
@@ -284,64 +309,61 @@
 {
 	usbmast_fun_t *mfun;
-	void *comm_buf = NULL;
-	size_t comm_size;
-	ipc_callid_t callid;
-	ipc_call_t call;
-	unsigned int flags;
-	sysarg_t method;
-	uint64_t ba;
-	size_t cnt;
-	int retval;
-
-	async_answer_0(iid, EOK);
-
-	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-	
-	(void) async_share_out_finalize(callid, &comm_buf);
-	if (comm_buf == AS_MAP_FAILED) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-	
+
 	mfun = (usbmast_fun_t *) ((ddf_fun_t *)arg)->driver_data;
-
-	while (true) {
-		callid = async_get_call(&call);
-		method = IPC_GET_IMETHOD(call);
-
-		if (!method) {
-			/* The other side hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-
-		switch (method) {
-		case BD_GET_BLOCK_SIZE:
-			async_answer_1(callid, EOK, mfun->block_size);
-			break;
-		case BD_GET_NUM_BLOCKS:
-			async_answer_2(callid, EOK, LOWER32(mfun->nblocks),
-			    UPPER32(mfun->nblocks));
-			break;
-		case BD_READ_BLOCKS:
-			ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			cnt = IPC_GET_ARG3(call);
-			retval = usbmast_read(mfun, ba, cnt, comm_buf);
-			async_answer_0(callid, retval);
-			break;
-		case BD_WRITE_BLOCKS:
-			ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			cnt = IPC_GET_ARG3(call);
-			retval = usbmast_write(mfun, ba, cnt, comm_buf);
-			async_answer_0(callid, retval);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
-}
+	bd_conn(iid, icall, &mfun->bd);
+}
+
+/** Open device. */
+static int usbmast_bd_open(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Close device. */
+static int usbmast_bd_close(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Read blocks from the device. */
+static int usbmast_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
+    size_t size)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+
+	if (size < cnt * mfun->block_size)
+		return EINVAL;
+
+	return usbmast_read(mfun, ba, cnt, buf);
+}
+
+/** Write blocks to the device. */
+static int usbmast_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
+    const void *buf, size_t size)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+
+	if (size < cnt * mfun->block_size)
+		return EINVAL;
+
+	return usbmast_write(mfun, ba, cnt, buf);
+}
+
+/** Get device block size. */
+static int usbmast_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+	*rsize = mfun->block_size;
+	return EOK;
+}
+
+/** Get number of blocks on device. */
+static int usbmast_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+	*rnb = mfun->nblocks;
+	return EOK;
+}
+
 
 /** USB mass storage driver ops. */
Index: uspace/drv/bus/usb/usbmast/usbmast.h
===================================================================
--- uspace/drv/bus/usb/usbmast/usbmast.h	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/drv/bus/usb/usbmast/usbmast.h	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -37,4 +37,5 @@
 #define USBMAST_H_
 
+#include <bd_srv.h>
 #include <sys/types.h>
 #include <usb/usb.h>
@@ -68,4 +69,6 @@
 	/** Block size in bytes */
 	size_t block_size;
+	/** Block device server structure */
+	bd_srv_t bd;
 } usbmast_fun_t;
 
Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/lib/block/libblock.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -40,5 +40,4 @@
 #include "../../srv/vfs/vfs.h"
 #include <ipc/loc.h>
-#include <ipc/bd.h>
 #include <ipc/services.h>
 #include <errno.h>
@@ -47,4 +46,5 @@
 #include <as.h>
 #include <assert.h>
+#include <bd.h>
 #include <fibril_synch.h>
 #include <adt/list.h>
@@ -80,7 +80,5 @@
 	service_id_t service_id;
 	async_sess_t *sess;
-	fibril_mutex_t comm_area_lock;
-	void *comm_area;
-	size_t comm_size;
+	bd_t *bd;
 	void *bb_buf;
 	aoff64_t bb_addr;
@@ -89,8 +87,6 @@
 } devcon_t;
 
-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 int read_blocks(devcon_t *, aoff64_t, size_t, void *, size_t);
+static int write_blocks(devcon_t *, aoff64_t, size_t, void *, size_t);
 static aoff64_t ba_ltop(devcon_t *, aoff64_t);
 
@@ -112,10 +108,7 @@
 
 static int devcon_add(service_id_t service_id, async_sess_t *sess,
-    size_t bsize, void *comm_area, size_t comm_size)
+    size_t bsize, bd_t *bd)
 {
 	devcon_t *devcon;
-	
-	if (comm_size < bsize)
-		return EINVAL;
 	
 	devcon = malloc(sizeof(devcon_t));
@@ -126,7 +119,5 @@
 	devcon->service_id = service_id;
 	devcon->sess = sess;
-	fibril_mutex_initialize(&devcon->comm_area_lock);
-	devcon->comm_area = comm_area;
-	devcon->comm_size = comm_size;
+	devcon->bd = bd;
 	devcon->bb_buf = NULL;
 	devcon->bb_addr = 0;
@@ -158,23 +149,14 @@
     size_t comm_size)
 {
-	void *comm_area = mmap(NULL, comm_size, PROTO_READ | PROTO_WRITE,
-	    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
-	if (!comm_area)
-		return ENOMEM;
-	
+	bd_t *bd;
+
 	async_sess_t *sess = loc_service_connect(mgmt, service_id,
 	    IPC_FLAG_BLOCKING);
 	if (!sess) {
-		munmap(comm_area, comm_size);
 		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);
-	async_exchange_end(exch);
-	
+	int rc = bd_open(sess, &bd);
 	if (rc != EOK) {
-		munmap(comm_area, comm_size);
 		async_hangup(sess);
 		return rc;
@@ -182,15 +164,14 @@
 	
 	size_t bsize;
-	rc = get_block_size(sess, &bsize);
-	
+	rc = bd_get_block_size(bd, &bsize);
 	if (rc != EOK) {
-		munmap(comm_area, comm_size);
+		bd_close(bd);
 		async_hangup(sess);
 		return rc;
 	}
 	
-	rc = devcon_add(service_id, sess, bsize, comm_area, comm_size);
+	rc = devcon_add(service_id, sess, bsize, bd);
 	if (rc != EOK) {
-		munmap(comm_area, comm_size);
+		bd_close(bd);
 		async_hangup(sess);
 		return rc;
@@ -213,5 +194,5 @@
 		free(devcon->bb_buf);
 	
-	munmap(devcon->comm_area, devcon->comm_size);
+	bd_close(devcon->bd);
 	async_hangup(devcon->sess);
 	
@@ -233,13 +214,9 @@
 		return ENOMEM;
 
-	fibril_mutex_lock(&devcon->comm_area_lock);
-	rc = read_blocks(devcon, 0, 1);
+	rc = read_blocks(devcon, 0, 1, bb_buf, devcon->pblock_size);
 	if (rc != EOK) {
-		fibril_mutex_unlock(&devcon->comm_area_lock);
 	    	free(bb_buf);
 		return rc;
 	}
-	memcpy(bb_buf, devcon->comm_area, devcon->pblock_size);
-	fibril_mutex_unlock(&devcon->comm_area_lock);
 
 	devcon->bb_buf = bb_buf;
@@ -338,6 +315,6 @@
 		list_remove(&b->free_link);
 		if (b->dirty) {
-			memcpy(devcon->comm_area, b->data, b->size);
-			rc = write_blocks(devcon, b->pba, cache->blocks_cluster);
+			rc = write_blocks(devcon, b->pba, cache->blocks_cluster,
+			    b->data, b->size);
 			if (rc != EOK)
 				return rc;
@@ -481,9 +458,6 @@
 				list_append(&b->free_link, &cache->free_list);
 				fibril_mutex_unlock(&cache->lock);
-				fibril_mutex_lock(&devcon->comm_area_lock);
-				memcpy(devcon->comm_area, b->data, b->size);
 				rc = write_blocks(devcon, b->pba,
-				    cache->blocks_cluster);
-				fibril_mutex_unlock(&devcon->comm_area_lock);
+				    cache->blocks_cluster, b->data, b->size);
 				if (rc != EOK) {
 					/*
@@ -555,8 +529,6 @@
 			 * the new contents from the device.
 			 */
-			fibril_mutex_lock(&devcon->comm_area_lock);
-			rc = read_blocks(devcon, b->pba, cache->blocks_cluster);
-			memcpy(b->data, devcon->comm_area, cache->lblock_size);
-			fibril_mutex_unlock(&devcon->comm_area_lock);
+			rc = read_blocks(devcon, b->pba, cache->blocks_cluster,
+			    b->data, cache->lblock_size);
 			if (rc != EOK) 
 				b->toxic = true;
@@ -616,8 +588,6 @@
 	if (block->dirty && (block->refcnt == 1) &&
 	    (blocks_cached > CACHE_HI_WATERMARK || mode != CACHE_MODE_WB)) {
-		fibril_mutex_lock(&devcon->comm_area_lock);
-		memcpy(devcon->comm_area, block->data, block->size);
-		rc = write_blocks(devcon, block->pba, cache->blocks_cluster);
-		fibril_mutex_unlock(&devcon->comm_area_lock);
+		rc = write_blocks(devcon, block->pba, cache->blocks_cluster,
+		    block->data, block->size);
 		block->dirty = false;
 	}
@@ -688,4 +658,5 @@
  *
  * @param service_id	Service ID of the block device.
+ * @param buf		Buffer for holding one block
  * @param bufpos	Pointer to the first unread valid offset within the
  * 			communication buffer.
@@ -699,6 +670,6 @@
  * @return		EOK on success or a negative return code on failure.
  */
-int block_seqread(service_id_t service_id, size_t *bufpos, size_t *buflen,
-    aoff64_t *pos, void *dst, size_t size)
+int block_seqread(service_id_t service_id, void *buf, size_t *bufpos,
+    size_t *buflen, aoff64_t *pos, void *dst, size_t size)
 {
 	size_t offset = 0;
@@ -711,5 +682,4 @@
 	block_size = devcon->pblock_size;
 	
-	fibril_mutex_lock(&devcon->comm_area_lock);
 	while (left > 0) {
 		size_t rd;
@@ -725,5 +695,5 @@
 			 * destination buffer.
 			 */
-			memcpy(dst + offset, devcon->comm_area + *bufpos, rd);
+			memcpy(dst + offset, buf + *bufpos, rd);
 			offset += rd;
 			*bufpos += rd;
@@ -736,7 +706,7 @@
 			int rc;
 
-			rc = read_blocks(devcon, *pos / block_size, 1);
+			rc = read_blocks(devcon, *pos / block_size, 1, buf,
+			    devcon->pblock_size);
 			if (rc != EOK) {
-				fibril_mutex_unlock(&devcon->comm_area_lock);
 				return rc;
 			}
@@ -746,5 +716,4 @@
 		}
 	}
-	fibril_mutex_unlock(&devcon->comm_area_lock);
 	
 	return EOK;
@@ -763,18 +732,9 @@
 {
 	devcon_t *devcon;
-	int rc;
 
 	devcon = devcon_search(service_id);
 	assert(devcon);
-	
-	fibril_mutex_lock(&devcon->comm_area_lock);
-
-	rc = read_blocks(devcon, ba, cnt);
-	if (rc == EOK)
-		memcpy(buf, devcon->comm_area, devcon->pblock_size * cnt);
-
-	fibril_mutex_unlock(&devcon->comm_area_lock);
-
-	return rc;
+
+	return read_blocks(devcon, ba, cnt, buf, devcon->pblock_size * cnt);
 }
 
@@ -792,17 +752,9 @@
 {
 	devcon_t *devcon;
-	int rc;
 
 	devcon = devcon_search(service_id);
 	assert(devcon);
-	
-	fibril_mutex_lock(&devcon->comm_area_lock);
-
-	memcpy(devcon->comm_area, data, devcon->pblock_size * cnt);
-	rc = write_blocks(devcon, ba, cnt);
-
-	fibril_mutex_unlock(&devcon->comm_area_lock);
-
-	return rc;
+
+	return write_blocks(devcon, ba, cnt, (void *)data, devcon->pblock_size * cnt);
 }
 
@@ -820,6 +772,6 @@
 	devcon = devcon_search(service_id);
 	assert(devcon);
-	
-	return get_block_size(devcon->sess, bsize);
+
+	return bd_get_block_size(devcon->bd, bsize);
 }
 
@@ -836,5 +788,5 @@
 	assert(devcon);
 	
-	return get_num_blocks(devcon->sess, nblocks);
+	return bd_get_num_blocks(devcon->bd, nblocks);
 }
 
@@ -887,5 +839,5 @@
 	memcpy(data, buffer + offset, bytes);
 	free(buffer);
-	
+
 	return EOK;
 }
@@ -903,25 +855,18 @@
 {
 	devcon_t *devcon = devcon_search(service_id);
-	assert(devcon);
-	
 	toc_block_t *toc = NULL;
-	
-	fibril_mutex_lock(&devcon->comm_area_lock);
-	
-	async_exch_t *exch = async_exchange_begin(devcon->sess);
-	int rc = async_req_1_0(exch, BD_READ_TOC, session);
-	async_exchange_end(exch);
-	
-	if (rc == EOK) {
-		toc = (toc_block_t *) malloc(sizeof(toc_block_t));
-		if (toc != NULL) {
-			memset(toc, 0, sizeof(toc_block_t));
-			memcpy(toc, devcon->comm_area,
-			    min(devcon->pblock_size, sizeof(toc_block_t)));
-		}
-	}
-	
-	
-	fibril_mutex_unlock(&devcon->comm_area_lock);
+	int rc;
+	
+	assert(devcon);
+	
+	toc = (toc_block_t *) malloc(sizeof(toc_block_t));
+	if (toc == NULL)
+		return NULL;
+	
+	rc = bd_read_toc(devcon->bd, session, toc, sizeof(toc_block_t));
+	if (rc != EOK) {
+		free(toc);
+		return NULL;
+	}
 	
 	return toc;
@@ -937,13 +882,10 @@
  * @return		EOK on success or negative error code on failure.
  */
-static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt)
-{
-	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);
-	
+static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt, void *buf,
+    size_t size)
+{
+	assert(devcon);
+	
+	int rc = bd_read_blocks(devcon->bd, ba, cnt, buf, size);
 	if (rc != EOK) {
 		printf("Error %d reading %zu blocks starting at block %" PRIuOFF64
@@ -967,13 +909,10 @@
  * @return		EOK on success or negative error code on failure.
  */
-static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt)
-{
-	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);
-	
+static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt, void *data,
+    size_t size)
+{
+	assert(devcon);
+	
+	int rc = bd_write_blocks(devcon->bd, ba, cnt, data, size);
 	if (rc != EOK) {
 		printf("Error %d writing %zu blocks starting at block %" PRIuOFF64
@@ -987,35 +926,4 @@
 }
 
-/** Get block size used by the device. */
-static int get_block_size(async_sess_t *sess, size_t *bsize)
-{
-	sysarg_t 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(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;
-}
-
 /** Convert logical block address to physical block address. */
 static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba)
Index: uspace/lib/block/libblock.h
===================================================================
--- uspace/lib/block/libblock.h	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/lib/block/libblock.h	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -122,6 +122,6 @@
 extern int block_put(block_t *);
 
-extern int block_seqread(service_id_t, size_t *, size_t *, aoff64_t *, void *,
-    size_t);
+extern int block_seqread(service_id_t, void *, size_t *, size_t *, aoff64_t *,
+    void *, size_t);
 
 extern int block_get_bsize(service_id_t, size_t *);
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/lib/c/Makefile	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -62,4 +62,6 @@
 	generic/ddi.c \
 	generic/as.c \
+	generic/bd.c \
+	generic/bd_srv.c \
 	generic/cap.c \
 	generic/cfg.c \
Index: uspace/lib/c/generic/bd.c
===================================================================
--- uspace/lib/c/generic/bd.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
+++ uspace/lib/c/generic/bd.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/**
+ * @file
+ * @brief IP link client stub
+ */
+
+#include <async.h>
+#include <assert.h>
+#include <bd.h>
+#include <errno.h>
+#include <ipc/bd.h>
+#include <ipc/services.h>
+#include <loc.h>
+#include <macros.h>
+#include <stdlib.h>
+
+static void bd_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg);
+
+int bd_open(async_sess_t *sess, bd_t **rbd)
+{
+	bd_t *bd = calloc(1, sizeof(bd_t));
+	if (bd == NULL)
+		return ENOMEM;
+	
+	bd->sess = sess;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	int rc = async_connect_to_me(exch, 0, 0, 0, bd_cb_conn, bd);
+	async_exchange_end(exch);
+	
+	if (rc != EOK)
+		goto error;
+	
+	*rbd = bd;
+	return EOK;
+	
+error:
+	if (bd != NULL)
+		free(bd);
+	
+	return rc;
+}
+
+void bd_close(bd_t *bd)
+{
+	/* XXX Synchronize with bd_cb_conn */
+	free(bd);
+}
+
+int bd_read_blocks(bd_t *bd, aoff64_t ba, size_t cnt, void *data, size_t size)
+{
+	async_exch_t *exch = async_exchange_begin(bd->sess);
+
+	ipc_call_t answer;
+	aid_t req = async_send_3(exch, BD_READ_BLOCKS, LOWER32(ba),
+	    UPPER32(ba), cnt, &answer);
+	int rc = async_data_read_start(exch, data, size);
+	async_exchange_end(exch);
+
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+
+	if (retval != EOK)
+		return retval;
+
+	return EOK;
+}
+
+int bd_read_toc(bd_t *bd, uint8_t session, void *buf, size_t size)
+{
+	async_exch_t *exch = async_exchange_begin(bd->sess);
+
+	ipc_call_t answer;
+	aid_t req = async_send_1(exch, BD_READ_TOC, session, &answer);
+	int rc = async_data_read_start(exch, buf, size);
+	async_exchange_end(exch);
+
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+
+	if (retval != EOK)
+		return retval;
+
+	return EOK;
+}
+
+int bd_write_blocks(bd_t *bd, aoff64_t ba, size_t cnt, const void *data,
+    size_t size)
+{
+	async_exch_t *exch = async_exchange_begin(bd->sess);
+
+	ipc_call_t answer;
+	aid_t req = async_send_3(exch, BD_WRITE_BLOCKS, LOWER32(ba),
+	    UPPER32(ba), cnt, &answer);
+	int rc = async_data_write_start(exch, data, size);
+	async_exchange_end(exch);
+
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+	if (retval != EOK)
+		return retval;
+
+	return EOK;
+}
+
+int bd_get_block_size(bd_t *bd, size_t *rbsize)
+{
+	sysarg_t bsize;
+	async_exch_t *exch = async_exchange_begin(bd->sess);
+
+	int rc = async_req_0_1(exch, BD_GET_BLOCK_SIZE, &bsize);
+	async_exchange_end(exch);
+
+	if (rc != EOK)
+		return rc;
+
+	*rbsize = bsize;
+	return EOK;
+}
+
+int bd_get_num_blocks(bd_t *bd, aoff64_t *rnb)
+{
+	sysarg_t nb_l;
+	sysarg_t nb_h;
+	async_exch_t *exch = async_exchange_begin(bd->sess);
+
+	int rc = async_req_0_2(exch, BD_GET_NUM_BLOCKS, &nb_l, &nb_h);
+	async_exchange_end(exch);
+
+	if (rc != EOK)
+		return rc;
+
+	*rnb = (aoff64_t) MERGE_LOUP32(nb_l, nb_h);
+	return EOK;
+}
+
+static void bd_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	bd_t *bd = (bd_t *)arg;
+
+	(void)bd;
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
+
+		switch (IPC_GET_IMETHOD(call)) {
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/bd_srv.c
===================================================================
--- uspace/lib/c/generic/bd_srv.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
+++ uspace/lib/c/generic/bd_srv.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Block device server stub
+ */
+#include <errno.h>
+#include <ipc/bd.h>
+#include <macros.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <bd_srv.h>
+
+static void bd_read_blocks_srv(bd_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	aoff64_t ba;
+	size_t cnt;
+	void *buf;
+	size_t size;
+	int rc;
+	ipc_callid_t rcallid;
+
+	ba = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
+	cnt = IPC_GET_ARG3(*call);
+
+	if (!async_data_read_receive(&rcallid, &size)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	buf = malloc(size);
+	if (buf == NULL) {
+		async_answer_0(rcallid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	if (srv->ops->read_blocks == NULL) {
+		async_answer_0(rcallid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->ops->read_blocks(srv, ba, cnt, buf, size);
+	if (rc != EOK) {
+		async_answer_0(rcallid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	async_data_read_finalize(rcallid, buf, size);
+
+	free(buf);
+	async_answer_0(callid, EOK);
+}
+
+static void bd_read_toc_srv(bd_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	uint8_t session;
+	void *buf;
+	size_t size;
+	int rc;
+	ipc_callid_t rcallid;
+
+	session = IPC_GET_ARG1(*call);
+
+	if (!async_data_read_receive(&rcallid, &size)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	buf = malloc(size);
+	if (buf == NULL) {
+		async_answer_0(rcallid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	if (srv->ops->read_toc == NULL) {
+		async_answer_0(rcallid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->ops->read_toc(srv, session, buf, size);
+	if (rc != EOK) {
+		async_answer_0(rcallid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	async_data_read_finalize(rcallid, buf, size);
+
+	free(buf);
+	async_answer_0(callid, EOK);
+}
+
+static void bd_write_blocks_srv(bd_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	aoff64_t ba;
+	size_t cnt;
+	void *data;
+	size_t size;
+	int rc;
+
+	ba = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
+	cnt = IPC_GET_ARG3(*call);
+
+	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	if (srv->ops->write_blocks == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->ops->write_blocks(srv, ba, cnt, data, size);
+	free(data);
+	async_answer_0(callid, rc);
+}
+
+static void bd_get_block_size_srv(bd_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	size_t block_size;
+
+	if (srv->ops->get_block_size == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->ops->get_block_size(srv, &block_size);
+	async_answer_1(callid, rc, block_size);
+}
+
+static void bd_get_num_blocks_srv(bd_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	aoff64_t num_blocks;
+
+	if (srv->ops->get_num_blocks == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->ops->get_num_blocks(srv, &num_blocks);
+	async_answer_2(callid, rc, LOWER32(num_blocks), UPPER32(num_blocks));
+}
+
+void bd_srv_init(bd_srv_t *srv)
+{
+	fibril_mutex_initialize(&srv->lock);
+	srv->connected = false;
+	srv->ops = NULL;
+	srv->arg = NULL;
+	srv->client_sess = NULL;
+}
+
+int bd_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	bd_srv_t *srv = (bd_srv_t *)arg;
+	int rc;
+
+	fibril_mutex_lock(&srv->lock);
+	if (srv->connected) {
+		fibril_mutex_unlock(&srv->lock);
+		async_answer_0(iid, EBUSY);
+		return EBUSY;
+	}
+
+	srv->connected = true;
+	fibril_mutex_unlock(&srv->lock);
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (sess == NULL)
+		return ENOMEM;
+
+	srv->client_sess = sess;
+
+	rc = srv->ops->open(srv);
+	if (rc != EOK)
+		return rc;
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		sysarg_t method = IPC_GET_IMETHOD(call);
+
+		if (!method) {
+			/* The other side has hung up */
+			fibril_mutex_lock(&srv->lock);
+			srv->connected = false;
+			fibril_mutex_unlock(&srv->lock);
+			async_answer_0(callid, EOK);
+			break;
+		}
+
+		switch (method) {
+		case BD_READ_BLOCKS:
+			bd_read_blocks_srv(srv, callid, &call);
+			break;
+		case BD_READ_TOC:
+			bd_read_toc_srv(srv, callid, &call);
+			break;
+		case BD_WRITE_BLOCKS:
+			bd_write_blocks_srv(srv, callid, &call);
+			break;
+		case BD_GET_BLOCK_SIZE:
+			bd_get_block_size_srv(srv, callid, &call);
+			break;
+		case BD_GET_NUM_BLOCKS:
+			bd_get_num_blocks_srv(srv, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, EINVAL);
+		}
+	}
+
+	return srv->ops->close(srv);
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/iplink_srv.c
===================================================================
--- uspace/lib/c/generic/iplink_srv.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/lib/c/generic/iplink_srv.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -139,4 +139,7 @@
 		if (!method) {
 			/* The other side has hung up */
+		    	fibril_mutex_lock(&srv->lock);
+			srv->connected = false;
+		    	fibril_mutex_unlock(&srv->lock);
 			async_answer_0(callid, EOK);
 			break;
Index: uspace/lib/c/include/bd.h
===================================================================
--- uspace/lib/c/include/bd.h	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
+++ uspace/lib/c/include/bd.h	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_BD_H_
+#define LIBC_BD_H_
+
+#include <async.h>
+#include <sys/types.h>
+
+typedef struct {
+	async_sess_t *sess;
+} bd_t;
+
+extern int bd_open(async_sess_t *, bd_t **);
+extern void bd_close(bd_t *);
+extern int bd_read_blocks(bd_t *, aoff64_t, size_t, void *, size_t);
+extern int bd_read_toc(bd_t *, uint8_t, void *, size_t);
+extern int bd_write_blocks(bd_t *, aoff64_t, size_t, const void *, size_t);
+extern int bd_get_block_size(bd_t *, size_t *);
+extern int bd_get_num_blocks(bd_t *, aoff64_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/bd_srv.h
===================================================================
--- uspace/lib/c/include/bd_srv.h	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
+++ uspace/lib/c/include/bd_srv.h	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_BD_SRV_H_
+#define LIBC_BD_SRV_H_
+
+#include <async.h>
+#include <fibril_synch.h>
+#include <bool.h>
+#include <sys/types.h>
+
+typedef struct bd_ops bd_ops_t;
+
+typedef struct {
+	fibril_mutex_t lock;
+	bool connected;
+	bd_ops_t *ops;
+	void *arg;
+	async_sess_t *client_sess;
+} bd_srv_t;
+
+typedef struct bd_ops {
+	int (*open)(bd_srv_t *);
+	int (*close)(bd_srv_t *);
+	int (*read_blocks)(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+	int (*read_toc)(bd_srv_t *, uint8_t, void *, size_t);
+	int (*write_blocks)(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+	int (*get_block_size)(bd_srv_t *, size_t *);
+	int (*get_num_blocks)(bd_srv_t *, aoff64_t *);
+} bd_ops_t;
+
+extern void bd_srv_init(bd_srv_t *);
+
+extern int bd_conn(ipc_callid_t, ipc_call_t *, void *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -51,7 +51,7 @@
 #include <libarch/ddi.h>
 #include <ddi.h>
-#include <ipc/bd.h>
 #include <async.h>
 #include <as.h>
+#include <bd_srv.h>
 #include <fibril_synch.h>
 #include <stdint.h>
@@ -98,13 +98,20 @@
 
 /** Per-disk state. */
-static disk_t disk[MAX_DISKS];
+static disk_t ata_disk[MAX_DISKS];
 
 static void print_syntax(void);
 static int ata_bd_init(void);
 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
-static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
-    void *buf);
-static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
-    const void *buf);
+
+static int ata_bd_open(bd_srv_t *);
+static int ata_bd_close(bd_srv_t *);
+static int ata_bd_read_blocks(bd_srv_t *, uint64_t ba, size_t cnt, void *buf,
+    size_t);
+static int ata_bd_read_toc(bd_srv_t *, uint8_t session, void *buf, size_t);
+static int ata_bd_write_blocks(bd_srv_t *, uint64_t ba, size_t cnt,
+    const void *buf, size_t);
+static int ata_bd_get_block_size(bd_srv_t *, size_t *);
+static int ata_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
+
 static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt,
     void *buf);
@@ -127,4 +134,19 @@
     unsigned timeout);
 
+static bd_ops_t ata_bd_ops = {
+	.open = ata_bd_open,
+	.close = ata_bd_close,
+	.read_blocks = ata_bd_read_blocks,
+	.read_toc = ata_bd_read_toc,
+	.write_blocks = ata_bd_write_blocks,
+	.get_block_size = ata_bd_get_block_size,
+	.get_num_blocks = ata_bd_get_num_blocks
+};
+
+static disk_t *bd_srv_disk(bd_srv_t *bd)
+{
+	return (disk_t *)bd->arg;
+}
+
 int main(int argc, char **argv)
 {
@@ -161,8 +183,8 @@
 		fflush(stdout);
 
-		rc = disk_init(&disk[i], i);
+		rc = disk_init(&ata_disk[i], i);
 
 		if (rc == EOK) {
-			disk_print_summary(&disk[i]);
+			disk_print_summary(&ata_disk[i]);
 		} else {
 			printf("Not found.\n");
@@ -174,9 +196,9 @@
 	for (i = 0; i < MAX_DISKS; i++) {
 		/* Skip unattached drives. */
-		if (disk[i].present == false)
+		if (ata_disk[i].present == false)
 			continue;
 		
 		snprintf(name, 16, "%s/ata%udisk%d", NAMESPACE, ctl_num, i);
-		rc = loc_service_register(name, &disk[i].service_id);
+		rc = loc_service_register(name, &ata_disk[i].service_id);
 		if (rc != EOK) {
 			printf(NAME ": Unable to register device %s.\n", name);
@@ -217,6 +239,6 @@
 		case am_chs:
 			printf("CHS %u cylinders, %u heads, %u sectors",
-			    disk->geom.cylinders, disk->geom.heads,
-			    disk->geom.sectors);
+			    d->geom.cylinders, d->geom.heads,
+			    d->geom.sectors);
 			break;
 		case am_lba28:
@@ -273,14 +295,5 @@
 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	void *fs_va = NULL;
-	ipc_callid_t callid;
-	ipc_call_t call;
-	sysarg_t method;
 	service_id_t dsid;
-	size_t comm_size;	/**< Size of the communication area. */
-	unsigned int flags;
-	int retval;
-	uint64_t ba;
-	size_t cnt;
 	int disk_id, i;
 
@@ -291,78 +304,13 @@
 	disk_id = -1;
 	for (i = 0; i < MAX_DISKS; i++)
-		if (disk[i].service_id == dsid)
+		if (ata_disk[i].service_id == dsid)
 			disk_id = i;
 
-	if (disk_id < 0 || disk[disk_id].present == false) {
+	if (disk_id < 0 || ata_disk[disk_id].present == false) {
 		async_answer_0(iid, EINVAL);
 		return;
 	}
 
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	(void) async_share_out_finalize(callid, &fs_va);
-	if (fs_va == AS_MAP_FAILED) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	while (true) {
-		callid = async_get_call(&call);
-		method = IPC_GET_IMETHOD(call);
-		
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-		
-		switch (method) {
-		case BD_READ_BLOCKS:
-			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
-			    IPC_GET_ARG2(call));
-			cnt = IPC_GET_ARG3(call);
-			if (cnt * disk[disk_id].block_size > comm_size) {
-				retval = ELIMIT;
-				break;
-			}
-			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 * disk[disk_id].block_size > comm_size) {
-				retval = ELIMIT;
-				break;
-			}
-			retval = ata_bd_write_blocks(disk_id, ba, cnt, fs_va);
-			break;
-		case BD_GET_BLOCK_SIZE:
-			async_answer_1(callid, EOK, disk[disk_id].block_size);
-			continue;
-		case BD_GET_NUM_BLOCKS:
-			async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
-			    UPPER32(disk[disk_id].blocks));
-			continue;
-		case BD_READ_TOC:
-			cnt = IPC_GET_ARG1(call);
-			if (disk[disk_id].dev_type == ata_pkt_dev)
-				retval = ata_pcmd_read_toc(disk_id, cnt, fs_va,
-				    disk[disk_id].block_size);
-			else
-				retval = EINVAL;
-			break;
-		default:
-			retval = EINVAL;
-			break;
-		}
-		async_answer_0(callid, retval);
-	}
+	bd_conn(iid, icall, &ata_disk[disk_id].bd);
 }
 
@@ -384,6 +332,11 @@
 	unsigned i;
 
+	d->disk_id = disk_id;
 	d->present = false;
 	fibril_mutex_initialize(&d->lock);
+
+	bd_srv_init(&d->bd);
+	d->bd.ops = &ata_bd_ops;
+	d->bd.arg = d;
 
 	/* Try identify command. */
@@ -514,16 +467,30 @@
 }
 
+static int ata_bd_open(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+static int ata_bd_close(bd_srv_t *bd)
+{
+	return EOK;
+}
+
 /** Read multiple blocks from the device. */
-static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
-    void *buf) {
-
+static int ata_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
+    void *buf, size_t size)
+{
+	disk_t *disk = bd_srv_disk(bd);
 	int rc;
 
+	if (size < cnt * disk->block_size)
+		return EINVAL;
+
 	while (cnt > 0) {
-		if (disk[disk_id].dev_type == ata_reg_dev)
-			rc = ata_rcmd_read(disk_id, ba, 1, buf);
+		if (disk->dev_type == ata_reg_dev)
+			rc = ata_rcmd_read(disk->disk_id, ba, 1, buf);
 		else
-			rc = ata_pcmd_read_12(disk_id, ba, 1, buf,
-			    disk[disk_id].block_size);
+			rc = ata_pcmd_read_12(disk->disk_id, ba, 1, buf,
+			    disk->block_size);
 
 		if (rc != EOK)
@@ -532,21 +499,33 @@
 		++ba;
 		--cnt;
-		buf += disk[disk_id].block_size;
-	}
-
-	return EOK;
+		buf += disk->block_size;
+	}
+
+	return EOK;
+}
+
+/** Read TOC from device. */
+static int ata_bd_read_toc(bd_srv_t *bd, uint8_t session, void *buf, size_t size)
+{
+	disk_t *disk = bd_srv_disk(bd);
+
+	return ata_pcmd_read_toc(disk->disk_id, session, buf, size);
 }
 
 /** Write multiple blocks to the device. */
-static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
-    const void *buf) {
-
+static int ata_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
+    const void *buf, size_t size)
+{
+	disk_t *disk = bd_srv_disk(bd);
 	int rc;
 
-	if (disk[disk_id].dev_type != ata_reg_dev)
+	if (disk->dev_type != ata_reg_dev)
 		return ENOTSUP;
 
+	if (size < cnt * disk->block_size)
+		return EINVAL;
+
 	while (cnt > 0) {
-		rc = ata_rcmd_write(disk_id, ba, 1, buf);
+		rc = ata_rcmd_write(disk->disk_id, ba, 1, buf);
 		if (rc != EOK)
 			return rc;
@@ -554,7 +533,25 @@
 		++ba;
 		--cnt;
-		buf += disk[disk_id].block_size;
-	}
-
+		buf += disk->block_size;
+	}
+
+	return EOK;
+}
+
+/** Get device block size. */
+static int ata_bd_get_block_size(bd_srv_t *bd, size_t *rbsize)
+{
+	disk_t *disk = bd_srv_disk(bd);
+
+	*rbsize = disk->block_size;
+	return EOK;
+}
+
+/** Get device number of blocks. */
+static int ata_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	disk_t *disk = bd_srv_disk(bd);
+
+	*rnb = disk->blocks;
 	return EOK;
 }
@@ -685,5 +682,5 @@
 	uint16_t val;
 
-	d = &disk[dev_idx];
+	d = &ata_disk[dev_idx];
 	fibril_mutex_lock(&d->lock);
 
@@ -874,5 +871,5 @@
 	block_coord_t bc;
 
-	d = &disk[disk_id];
+	d = &ata_disk[disk_id];
 	
 	/* Silence warning. */
@@ -919,5 +916,5 @@
 		/* Read data from the device buffer. */
 
-		for (i = 0; i < disk[disk_id].block_size / 2; i++) {
+		for (i = 0; i < ata_disk[disk_id].block_size / 2; i++) {
 			data = pio_read_16(&cmd->data_port);
 			((uint16_t *) buf)[i] = data;
@@ -950,5 +947,5 @@
 	block_coord_t bc;
 
-	d = &disk[disk_id];
+	d = &ata_disk[disk_id];
 	
 	/* Silence warning. */
@@ -995,5 +992,5 @@
 		/* Write data to the device buffer. */
 
-		for (i = 0; i < disk[disk_id].block_size / 2; i++) {
+		for (i = 0; i < d->block_size / 2; i++) {
 			pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
 		}
Index: uspace/srv/bd/ata_bd/ata_bd.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.h	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/ata_bd/ata_bd.h	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -36,4 +36,5 @@
 #define __ATA_BD_H__
 
+#include <bd_srv.h>
 #include <sys/types.h>
 #include <fibril_synch.h>
@@ -117,4 +118,6 @@
 	fibril_mutex_t lock;
 	service_id_t service_id;
+	int disk_id;
+	bd_srv_t bd;
 } disk_t;
 
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -41,7 +41,7 @@
 #include <stdio.h>
 #include <unistd.h>
-#include <ipc/bd.h>
 #include <async.h>
 #include <as.h>
+#include <bd_srv.h>
 #include <fibril_synch.h>
 #include <loc.h>
@@ -62,4 +62,5 @@
 
 static service_id_t service_id;
+static bd_srv_t bd_srv;
 static fibril_mutex_t dev_lock;
 
@@ -67,6 +68,20 @@
 static int file_bd_init(const char *fname);
 static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
-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);
+
+static int file_bd_open(bd_srv_t *);
+static int file_bd_close(bd_srv_t *);
+static int file_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+static int file_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+static int file_bd_get_block_size(bd_srv_t *, size_t *);
+static int file_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
+
+static bd_ops_t file_bd_ops = {
+	.open = file_bd_open,
+	.close = file_bd_close,
+	.read_blocks = file_bd_read_blocks,
+	.write_blocks = file_bd_write_blocks,
+	.get_block_size = file_bd_get_block_size,
+	.get_num_blocks = file_bd_get_num_blocks
+};
 
 int main(int argc, char **argv)
@@ -139,4 +154,7 @@
 static int file_bd_init(const char *fname)
 {
+	bd_srv_init(&bd_srv);
+	bd_srv.ops = &file_bd_ops;
+	
 	async_set_client_connection(file_bd_connection);
 	int rc = loc_server_register(NAME);
@@ -170,79 +188,28 @@
 static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	void *fs_va = NULL;
-	ipc_callid_t callid;
-	ipc_call_t call;
-	sysarg_t method;
-	size_t comm_size;
-	unsigned int flags;
-	int retval;
-	uint64_t ba;
-	size_t cnt;
-
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	(void) async_share_out_finalize(callid, &fs_va);
-	if (fs_va == AS_MAP_FAILED) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	while (true) {
-		callid = async_get_call(&call);
-		method = IPC_GET_IMETHOD(call);
-		
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-		
-		switch (method) {
-		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 = 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:
-			async_answer_1(callid, EOK, block_size);
-			continue;
-		case BD_GET_NUM_BLOCKS:
-			async_answer_2(callid, EOK, LOWER32(num_blocks),
-			    UPPER32(num_blocks));
-			continue;
-		default:
-			retval = EINVAL;
-			break;
-		}
-		async_answer_0(callid, retval);
-	}
+	bd_conn(iid, icall, &bd_srv);
+}
+
+/** Open device. */
+static int file_bd_open(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Close device. */
+static int file_bd_close(bd_srv_t *bd)
+{
+	return EOK;
 }
 
 /** Read blocks from the device. */
-static int file_bd_read_blocks(uint64_t ba, size_t cnt, void *buf)
+static int file_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
+    size_t size)
 {
 	size_t n_rd;
 	int rc;
+
+	if (size < cnt * block_size)
+		return EINVAL;
 
 	/* Check whether access is within device address bounds. */
@@ -279,8 +246,12 @@
 
 /** Write blocks to the device. */
-static int file_bd_write_blocks(uint64_t ba, size_t cnt, const void *buf)
+static int file_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
+    const void *buf, size_t size)
 {
 	size_t n_wr;
 	int rc;
+
+	if (size < cnt * block_size)
+		return EINVAL;
 
 	/* Check whether access is within device address bounds. */
@@ -318,4 +289,18 @@
 }
 
+/** Get device block size. */
+static int file_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
+{
+	*rsize = block_size;
+	return EOK;
+}
+
+/** Get number of blocks on device. */
+static int file_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	*rnb = num_blocks;
+	return EOK;
+}
+
 /**
  * @}
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -39,7 +39,7 @@
 #include <libarch/ddi.h>
 #include <ddi.h>
-#include <ipc/bd.h>
 #include <async.h>
 #include <as.h>
+#include <bd_srv.h>
 #include <fibril_synch.h>
 #include <loc.h>
@@ -65,4 +65,5 @@
 };
 
+/** GXE disk hardware registers */
 typedef struct {
 	uint32_t offset_lo;
@@ -83,25 +84,49 @@
 
 	uint8_t buffer[512];
+} gxe_bd_hw_t;
+
+/** GXE block device soft state */
+typedef struct {
+	/** Block device server structure */
+	bd_srv_t bd;
+	int disk_id;
 } gxe_bd_t;
 
-
 static const size_t block_size = 512;
-static size_t comm_size;
 
 static uintptr_t dev_physical = 0x13000000;
-static gxe_bd_t *dev;
+static gxe_bd_hw_t *dev;
 
 static service_id_t service_id[MAX_DISKS];
 
 static fibril_mutex_t dev_lock[MAX_DISKS];
+
+static gxe_bd_t gxe_bd[MAX_DISKS];
 
 static int gxe_bd_init(void);
 static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
-static int gxe_bd_read_blocks(int disk_id, uint64_t ba, unsigned cnt,
-    void *buf);
-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);
+
+static int gxe_bd_open(bd_srv_t *);
+static int gxe_bd_close(bd_srv_t *);
+static int gxe_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+static int gxe_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+static int gxe_bd_get_block_size(bd_srv_t *, size_t *);
+static int gxe_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
+
+static bd_ops_t gxe_bd_ops = {
+	.open = gxe_bd_open,
+	.close = gxe_bd_close,
+	.read_blocks = gxe_bd_read_blocks,
+	.write_blocks = gxe_bd_write_blocks,
+	.get_block_size = gxe_bd_get_block_size,
+	.get_num_blocks = gxe_bd_get_num_blocks
+};
+
+static gxe_bd_t *bd_srv_gxe(bd_srv_t *bd)
+{
+	return (gxe_bd_t *)bd->arg;
+}
 
 int main(int argc, char **argv)
@@ -130,5 +155,5 @@
 	
 	void *vaddr;
-	rc = pio_enable((void *) dev_physical, sizeof(gxe_bd_t), &vaddr);
+	rc = pio_enable((void *) dev_physical, sizeof(gxe_bd_hw_t), &vaddr);
 	if (rc != EOK) {
 		printf("%s: Could not initialize device I/O space.\n", NAME);
@@ -140,4 +165,8 @@
 	for (unsigned int i = 0; i < MAX_DISKS; i++) {
 		char name[16];
+		
+		bd_srv_init(&gxe_bd[i].bd);
+		gxe_bd[i].bd.ops = &gxe_bd_ops;
+		gxe_bd[i].bd.arg = (void *)&gxe_bd[i];
 		
 		snprintf(name, 16, "%s/disk%u", NAMESPACE, i);
@@ -157,13 +186,5 @@
 static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	void *fs_va = NULL;
-	ipc_callid_t callid;
-	ipc_call_t call;
-	sysarg_t method;
 	service_id_t dsid;
-	unsigned int flags;
-	int retval;
-	uint64_t ba;
-	unsigned cnt;
 	int disk_id, i;
 
@@ -182,73 +203,28 @@
 	}
 
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	if (comm_size < block_size) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	(void) async_share_out_finalize(callid, &fs_va);
-	if (fs_va == AS_MAP_FAILED) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	while (true) {
-		callid = async_get_call(&call);
-		method = IPC_GET_IMETHOD(call);
-		
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-		
-		switch (method) {
-		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 = 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:
-			async_answer_1(callid, EOK, block_size);
-			continue;
-		case BD_GET_NUM_BLOCKS:
-			retval = ENOTSUP;
-			break;
-		default:
-			retval = EINVAL;
-			break;
-		}
-		async_answer_0(callid, retval);
-	}
+	bd_conn(iid, icall, &gxe_bd[disk_id].bd);
+}
+
+/** Open device. */
+static int gxe_bd_open(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Close device. */
+static int gxe_bd_close(bd_srv_t *bd)
+{
+	return EOK;
 }
 
 /** Read multiple blocks from the device. */
-static int gxe_bd_read_blocks(int disk_id, uint64_t ba, unsigned cnt,
-    void *buf) {
-
+static int gxe_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
+    void *buf, size_t size)
+{
+	int disk_id = bd_srv_gxe(bd)->disk_id;
 	int rc;
+
+	if (size < cnt * block_size)
+		return EINVAL;
 
 	while (cnt > 0) {
@@ -266,8 +242,12 @@
 
 /** Write multiple blocks to the device. */
-static int gxe_bd_write_blocks(int disk_id, uint64_t ba, unsigned cnt,
-    const void *buf) {
-
+static int gxe_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
+    const void *buf, size_t size)
+{
+	int disk_id = bd_srv_gxe(bd)->disk_id;
 	int rc;
+
+	if (size < cnt * block_size)
+		return EINVAL;
 
 	while (cnt > 0) {
@@ -282,4 +262,17 @@
 
 	return EOK;
+}
+
+/** Get device block size. */
+static int gxe_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
+{
+	*rsize = block_size;
+	return EOK;
+}
+
+/** Get number of blocks on device. */
+static int gxe_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	return ENOTSUP;
 }
 
Index: uspace/srv/bd/part/guid_part/guid_part.c
===================================================================
--- uspace/srv/bd/part/guid_part/guid_part.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/part/guid_part/guid_part.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -47,7 +47,7 @@
 #include <stdlib.h>
 #include <unistd.h>
-#include <ipc/bd.h>
 #include <async.h>
 #include <as.h>
+#include <bd_srv.h>
 #include <fibril_synch.h>
 #include <loc.h>
@@ -83,4 +83,6 @@
 	/** Service representing the partition (outbound device) */
 	service_id_t dsid;
+	/** Block device server structure */
+	bd_srv_t bd;
 	/** Points to next partition structure. */
 	struct part *next;
@@ -100,7 +102,26 @@
 static void gpt_pte_to_part(const gpt_entry_t *pte, part_t *part);
 static void gpt_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
-static int gpt_bd_read(part_t *p, aoff64_t ba, size_t cnt, void *buf);
-static int gpt_bd_write(part_t *p, aoff64_t ba, size_t cnt, const void *buf);
 static int gpt_bsa_translate(part_t *p, aoff64_t ba, size_t cnt, aoff64_t *gba);
+
+static int gpt_bd_open(bd_srv_t *);
+static int gpt_bd_close(bd_srv_t *);
+static int gpt_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+static int gpt_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+static int gpt_bd_get_block_size(bd_srv_t *, size_t *);
+static int gpt_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
+
+static bd_ops_t gpt_bd_ops = {
+	.open = gpt_bd_open,
+	.close = gpt_bd_close,
+	.read_blocks = gpt_bd_read_blocks,
+	.write_blocks = gpt_bd_write_blocks,
+	.get_block_size = gpt_bd_get_block_size,
+	.get_num_blocks = gpt_bd_get_num_blocks
+};
+
+static part_t *bd_srv_part(bd_srv_t *bd)
+{
+	return (part_t *)bd->arg;
+}
 
 int main(int argc, char **argv)
@@ -304,4 +325,8 @@
 	}
 
+	bd_srv_init(&part->bd);
+	part->bd.ops = &gpt_bd_ops;
+	part->bd.arg = part;
+
 	part->dsid = 0;
 	part->next = NULL;
@@ -310,14 +335,5 @@
 static void gpt_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	size_t comm_size;
-	void *fs_va = NULL;
-	ipc_callid_t callid;
-	ipc_call_t call;
-	sysarg_t method;
 	service_id_t dh;
-	unsigned int flags;
-	int retval;
-	aoff64_t ba;
-	size_t cnt;
 	part_t *part;
 
@@ -341,68 +357,28 @@
 	assert(part->present == true);
 
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	(void) async_share_out_finalize(callid, &fs_va);
-	if (fs_va == AS_MAP_FAILED) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	while (true) {
-		callid = async_get_call(&call);
-		method = IPC_GET_IMETHOD(call);
-		
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-		
-		switch (method) {
-		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 = gpt_bd_read(part, 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 = gpt_bd_write(part, ba, cnt, fs_va);
-			break;
-		case BD_GET_BLOCK_SIZE:
-			async_answer_1(callid, EOK, block_size);
-			continue;
-		case BD_GET_NUM_BLOCKS:
-			async_answer_2(callid, EOK, LOWER32(part->length),
-			    UPPER32(part->length));
-			continue;
-		default:
-			retval = EINVAL;
-			break;
-		}
-		async_answer_0(callid, retval);
-	}
+	bd_conn(iid, icall, &part->bd);
+}
+
+/** Open device. */
+static int gpt_bd_open(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Close device. */
+static int gpt_bd_close(bd_srv_t *bd)
+{
+	return EOK;
 }
 
 /** Read blocks from partition. */
-static int gpt_bd_read(part_t *p, aoff64_t ba, size_t cnt, void *buf)
-{
+static int gpt_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf,
+    size_t size)
+{
+	part_t *p = bd_srv_part(bd);
 	aoff64_t gba;
+
+	if (cnt * block_size < size)
+		return EINVAL;
 
 	if (gpt_bsa_translate(p, ba, cnt, &gba) != EOK)
@@ -413,7 +389,12 @@
 
 /** Write blocks to partition. */
-static int gpt_bd_write(part_t *p, aoff64_t ba, size_t cnt, const void *buf)
-{
+static int gpt_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
+    const void *buf, size_t size)
+{
+	part_t *p = bd_srv_part(bd);
 	aoff64_t gba;
+
+	if (cnt * block_size < size)
+		return EINVAL;
 
 	if (gpt_bsa_translate(p, ba, cnt, &gba) != EOK)
@@ -422,4 +403,21 @@
 	return block_write_direct(indev_sid, gba, cnt, buf);
 }
+
+/** Get device block size. */
+static int gpt_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
+{
+	*rsize = block_size;
+	return EOK;
+}
+
+/** Get number of blocks on device. */
+static int gpt_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	part_t *part = bd_srv_part(bd);
+
+	*rnb = part->length;
+	return EOK;
+}
+
 
 /** Translate block segment address with range checking. */
Index: uspace/srv/bd/part/mbr_part/mbr_part.c
===================================================================
--- uspace/srv/bd/part/mbr_part/mbr_part.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/part/mbr_part/mbr_part.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -44,5 +44,5 @@
  *
  * Referemces:
- *	
+ *
  * The source of MBR structures for this driver have been the following
  * Wikipedia articles:
@@ -57,7 +57,7 @@
 #include <stdlib.h>
 #include <unistd.h>
-#include <ipc/bd.h>
 #include <async.h>
 #include <as.h>
+#include <bd_srv.h>
 #include <fibril_synch.h>
 #include <loc.h>
@@ -100,4 +100,6 @@
 	/** Device representing the partition (outbound device) */
 	service_id_t dsid;
+	/** Block device server structure */
+	bd_srv_t bd;
 	/** Points to next partition structure. */
 	struct part *next;
@@ -140,5 +142,5 @@
 
 /** Partitioned device (inbound device) */
-static service_id_t indef_sid;
+static service_id_t indev_sid;
 
 /** List of partitions. This structure is an empty head. */
@@ -150,7 +152,26 @@
 static void mbr_pte_to_part(uint32_t base, const pt_entry_t *pte, part_t *part);
 static void mbr_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
-static int mbr_bd_read(part_t *p, uint64_t ba, size_t cnt, void *buf);
-static int mbr_bd_write(part_t *p, uint64_t ba, size_t cnt, const void *buf);
 static int mbr_bsa_translate(part_t *p, uint64_t ba, size_t cnt, uint64_t *gba);
+
+static int mbr_bd_open(bd_srv_t *);
+static int mbr_bd_close(bd_srv_t *);
+static int mbr_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+static int mbr_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+static int mbr_bd_get_block_size(bd_srv_t *, size_t *);
+static int mbr_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
+
+static bd_ops_t mbr_bd_ops = {
+	.open = mbr_bd_open,
+	.close = mbr_bd_close,
+	.read_blocks = mbr_bd_read_blocks,
+	.write_blocks = mbr_bd_write_blocks,
+	.get_block_size = mbr_bd_get_block_size,
+	.get_num_blocks = mbr_bd_get_num_blocks
+};
+
+static part_t *bd_srv_part(bd_srv_t *bd)
+{
+	return (part_t *)bd->arg;
+}
 
 int main(int argc, char **argv)
@@ -183,5 +204,5 @@
 	part_t *part;
 
-	rc = loc_service_get_id(dev_name, &indef_sid, 0);
+	rc = loc_service_get_id(dev_name, &indev_sid, 0);
 	if (rc != EOK) {
 		printf(NAME ": could not resolve device `%s'.\n", dev_name);
@@ -189,5 +210,5 @@
 	}
 
-	rc = block_init(EXCHANGE_SERIALIZE, indef_sid, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, indev_sid, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": could not init libblock.\n");
@@ -197,5 +218,5 @@
 	/* Determine and verify block size. */
 
-	rc = block_get_bsize(indef_sid, &block_size);
+	rc = block_get_bsize(indev_sid, &block_size);
 	if (rc != EOK) {
 		printf(NAME ": error getting block size.\n");
@@ -281,5 +302,5 @@
 	 */
 
-	rc = block_read_direct(indef_sid, 0, 1, brb);
+	rc = block_read_direct(indev_sid, 0, 1, brb);
 	if (rc != EOK) {
 		printf(NAME ": Failed reading MBR block.\n");
@@ -332,5 +353,5 @@
 		 */
 		ba = cp.start_addr;
-		rc = block_read_direct(indef_sid, ba, 1, brb);
+		rc = block_read_direct(indev_sid, ba, 1, brb);
 		if (rc != EOK) {
 			printf(NAME ": Failed reading EBR block at %"
@@ -381,4 +402,8 @@
 	part->present = (pte->ptype != PT_UNUSED) ? true : false;
 
+	bd_srv_init(&part->bd);
+	part->bd.ops = &mbr_bd_ops;
+	part->bd.arg = part;
+
 	part->dsid = 0;
 	part->next = NULL;
@@ -387,14 +412,5 @@
 static void mbr_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	size_t comm_size;
-	void *fs_va = NULL;
-	ipc_callid_t callid;
-	ipc_call_t call;
-	sysarg_t method;
 	service_id_t dh;
-	unsigned int flags;
-	int retval;
-	uint64_t ba;
-	size_t cnt;
 	part_t *part;
 
@@ -417,85 +433,65 @@
 
 	assert(part->present == true);
-
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	(void) async_share_out_finalize(callid, &fs_va);
-	if (fs_va == AS_MAP_FAILED) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	while (1) {
-		callid = async_get_call(&call);
-		method = IPC_GET_IMETHOD(call);
-		
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-		
-		switch (method) {
-		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 = mbr_bd_read(part, 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 = mbr_bd_write(part, ba, cnt, fs_va);
-			break;
-		case BD_GET_BLOCK_SIZE:
-			async_answer_1(callid, EOK, block_size);
-			continue;
-		case BD_GET_NUM_BLOCKS:
-			async_answer_2(callid, EOK, LOWER32(part->length),
-			    UPPER32(part->length));
-			continue;
-		default:
-			retval = EINVAL;
-			break;
-		}
-		async_answer_0(callid, retval);
-	}
+	bd_conn(iid, icall, &part->bd);
+}
+
+/** Open device. */
+static int mbr_bd_open(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Close device. */
+static int mbr_bd_close(bd_srv_t *bd)
+{
+	return EOK;
 }
 
 /** Read blocks from partition. */
-static int mbr_bd_read(part_t *p, uint64_t ba, size_t cnt, void *buf)
-{
-	uint64_t gba;
+static int mbr_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf,
+    size_t size)
+{
+	part_t *p = bd_srv_part(bd);
+	aoff64_t gba;
+
+	if (cnt * block_size < size)
+		return EINVAL;
 
 	if (mbr_bsa_translate(p, ba, cnt, &gba) != EOK)
 		return ELIMIT;
 
-	return block_read_direct(indef_sid, gba, cnt, buf);
+	return block_read_direct(indev_sid, gba, cnt, buf);
 }
 
 /** Write blocks to partition. */
-static int mbr_bd_write(part_t *p, uint64_t ba, size_t cnt, const void *buf)
-{
-	uint64_t gba;
+static int mbr_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
+    const void *buf, size_t size)
+{
+	part_t *p = bd_srv_part(bd);
+	aoff64_t gba;
+
+	if (cnt * block_size < size)
+		return EINVAL;
 
 	if (mbr_bsa_translate(p, ba, cnt, &gba) != EOK)
 		return ELIMIT;
 
-	return block_write_direct(indef_sid, gba, cnt, buf);
+	return block_write_direct(indev_sid, gba, cnt, buf);
+}
+
+/** Get device block size. */
+static int mbr_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
+{
+	*rsize = block_size;
+	return EOK;
+}
+
+/** Get number of blocks on device. */
+static int mbr_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	part_t *part = bd_srv_part(bd);
+
+	*rnb = part->length;
+	return EOK;
 }
 
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/rd/rd.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -43,4 +43,5 @@
 #include <sysinfo.h>
 #include <as.h>
+#include <bd_srv.h>
 #include <ddi.h>
 #include <align.h>
@@ -53,5 +54,4 @@
 #include <stdio.h>
 #include <loc.h>
-#include <ipc/bd.h>
 #include <macros.h>
 #include <inttypes.h>
@@ -68,6 +68,10 @@
 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);
+static int rd_open(bd_srv_t *);
+static int rd_close(bd_srv_t *);
+static int rd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+static int rd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+static int rd_get_block_size(bd_srv_t *, size_t *);
+static int rd_get_num_blocks(bd_srv_t *, aoff64_t *);
 
 /** This rwlock protects the ramdisk's data.
@@ -78,102 +82,37 @@
  *
  */
-fibril_rwlock_t rd_lock;
-
-/** Handle one connection to ramdisk.
- *
- * @param iid   Hash of the request that opened the connection.
- * @param icall Call data of the request that opened the connection.
- */
-static void rd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	ipc_callid_t callid;
-	ipc_call_t call;
-	int retval;
-	void *fs_va = NULL;
-	uint64_t ba;
-	size_t cnt;
-	size_t comm_size;
-	
-	/*
-	 * Answer the first IPC_M_CONNECT_ME_TO call.
-	 */
-	async_answer_0(iid, EOK);
-	
-	/*
-	 * Now we wait for the client to send us its communication as_area.
-	 */
-	unsigned int flags;
-	if (async_share_out_receive(&callid, &comm_size, &flags)) {
-		(void) async_share_out_finalize(callid, &fs_va);
-		if (fs_va == AS_MAP_FAILED) {
-			async_answer_0(callid, EHANGUP);
-			return;
-		}
-	} else {
-		/*
-		 * The client doesn't speak the same protocol.
-		 * At this point we can't handle protocol variations.
-		 * Close the connection.
-		 */
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-	
-	while (true) {
-		callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call)) {
-			/*
-			 * The other side has hung up.
-			 * Exit the fibril.
-			 */
-			async_answer_0(callid, EOK);
-			return;
-		}
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		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 = 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;
-			}
-			retval = rd_write_blocks(ba, cnt, fs_va);
-			break;
-		case BD_GET_BLOCK_SIZE:
-			async_answer_1(callid, EOK, block_size);
-			continue;
-		case BD_GET_NUM_BLOCKS:
-			async_answer_2(callid, EOK, LOWER32(rd_size / block_size),
-			    UPPER32(rd_size / block_size));
-			continue;
-		default:
-			/*
-			 * The client doesn't speak the same protocol.
-			 * Instead of closing the connection, we just ignore
-			 * the call. This can be useful if the client uses a
-			 * newer version of the protocol.
-			 */
-			retval = EINVAL;
-			break;
-		}
-		async_answer_0(callid, retval);
-	}
+static fibril_rwlock_t rd_lock;
+
+static bd_ops_t rd_bd_ops = {
+	.open = rd_open,
+	.close = rd_close,
+	.read_blocks = rd_read_blocks,
+	.write_blocks = rd_write_blocks,
+	.get_block_size = rd_get_block_size,
+	.get_num_blocks = rd_get_num_blocks
+};
+
+static bd_srv_t bd_srv;
+
+static void rd_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	bd_conn(iid, icall, &bd_srv);
+}
+
+/** Open device. */
+static int rd_open(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Close device. */
+static int rd_close(bd_srv_t *bd)
+{
+	return EOK;
 }
 
 /** Read blocks from the device. */
-static int rd_read_blocks(uint64_t ba, size_t cnt, void *buf)
+static int rd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf,
+    size_t size)
 {
 	if ((ba + cnt) * block_size > rd_size) {
@@ -183,5 +122,5 @@
 	
 	fibril_rwlock_read_lock(&rd_lock);
-	memcpy(buf, rd_addr + ba * block_size, block_size * cnt);
+	memcpy(buf, rd_addr + ba * block_size, min(block_size * cnt, size));
 	fibril_rwlock_read_unlock(&rd_lock);
 	
@@ -190,5 +129,6 @@
 
 /** Write blocks to the device. */
-static int rd_write_blocks(uint64_t ba, size_t cnt, const void *buf)
+static int rd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
+    const void *buf, size_t size)
 {
 	if ((ba + cnt) * block_size > rd_size) {
@@ -198,5 +138,5 @@
 	
 	fibril_rwlock_write_lock(&rd_lock);
-	memcpy(rd_addr + ba * block_size, buf, block_size * cnt);
+	memcpy(rd_addr + ba * block_size, buf, min(block_size * cnt, size));
 	fibril_rwlock_write_unlock(&rd_lock);
 	
@@ -235,5 +175,8 @@
 	    (void *) addr_phys, size);
 	
-	async_set_client_connection(rd_connection);
+	bd_srv_init(&bd_srv);
+	bd_srv.ops = &rd_bd_ops;
+	
+	async_set_client_connection(rd_client_conn);
 	ret = loc_server_register(NAME);
 	if (ret != EOK) {
@@ -254,4 +197,18 @@
 }
 
+/** Get device block size. */
+static int rd_get_block_size(bd_srv_t *bd, size_t *rsize)
+{
+	*rsize = block_size;
+	return EOK;
+}
+
+/** Get number of blocks on device. */
+static int rd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	*rnb = rd_size / block_size;
+	return EOK;
+}
+
 int main(int argc, char **argv)
 {
Index: uspace/srv/bd/sata_bd/sata_bd.c
===================================================================
--- uspace/srv/bd/sata_bd/sata_bd.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/sata_bd/sata_bd.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -38,7 +38,7 @@
 
 #include <sys/types.h>
+#include <bd_srv.h>
 #include <errno.h>
 #include <stdio.h>
-#include <ipc/bd.h>
 #include <str.h>
 #include <loc.h>
@@ -56,4 +56,25 @@
 static sata_bd_dev_t disk[MAXDISKS];
 static int disk_count;
+
+static int sata_bd_open(bd_srv_t *);
+static int sata_bd_close(bd_srv_t *);
+static int sata_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+static int sata_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+static int sata_bd_get_block_size(bd_srv_t *, size_t *);
+static int sata_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
+
+static bd_ops_t sata_bd_ops = {
+	.open = sata_bd_open,
+	.close = sata_bd_close,
+	.read_blocks = sata_bd_read_blocks,
+	.write_blocks = sata_bd_write_blocks,
+	.get_block_size = sata_bd_get_block_size,
+	.get_num_blocks = sata_bd_get_num_blocks
+};
+
+static sata_bd_dev_t *bd_srv_sata(bd_srv_t *bd)
+{
+	return (sata_bd_dev_t *)bd->arg;
+}
 
 /** Find SATA devices in device tree.
@@ -82,5 +103,9 @@
 		
 		ahci_get_num_blocks(disk[disk_count].sess, &disk[disk_count].blocks);
-				
+		
+		bd_srv_init(&disk[disk_count].bd);
+		disk[disk_count].bd.ops = &sata_bd_ops;
+		disk[disk_count].bd.arg = &disk[disk_count];
+		
 		printf("Device %s - %s , blocks: %lu, block_size: %lu\n", 
 		    disk[disk_count].dev_name, disk[disk_count].sata_dev_name,
@@ -141,15 +166,5 @@
 static void sata_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	void *fs_va = NULL;
-	ipc_callid_t callid;
-	ipc_call_t call;
-	sysarg_t method;
 	service_id_t dsid;
-	/* Size of the communication area. */
-	size_t comm_size;	
-	unsigned int flags;
-	int retval = 0;
-	uint64_t ba;
-	size_t cnt;
 	int disk_id, i;
 
@@ -168,61 +183,61 @@
 	}
 
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	(void) async_share_out_finalize(callid, &fs_va);
-	if (fs_va == (void *) -1) {
-		async_answer_0(callid, EHANGUP);
-		return;
-	}
-
-	while (true) {
-		callid = async_get_call(&call);
-		method = IPC_GET_IMETHOD(call);
-		
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-		
-		switch (method) {
-			case BD_READ_BLOCKS:
-				ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-				cnt = IPC_GET_ARG3(call);
-				if (cnt * disk[disk_id].block_size > comm_size) {
-					retval = ELIMIT;
-					break;
-				}
-				retval = ahci_read_blocks(disk[disk_id].sess, 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 * disk[disk_id].block_size > comm_size) {
-					retval = ELIMIT;
-					break;
-				}
-				retval = ahci_write_blocks(disk[disk_id].sess, ba, cnt, fs_va);
-				break;
-			case BD_GET_BLOCK_SIZE:
-				async_answer_1(callid, EOK, disk[disk_id].block_size);
-				continue;
-			case BD_GET_NUM_BLOCKS:
-				async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
-				    UPPER32(disk[disk_id].blocks));
-				break;
-			default:
-				retval = EINVAL;
-				break;
-			}
-		async_answer_0(callid, retval);
-	}
-}
+	bd_conn(iid, icall, &disk[disk_id].bd);
+}
+
+/** Open device. */
+static int sata_bd_open(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Close device. */
+static int sata_bd_close(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Read blocks from partition. */
+static int sata_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf,
+    size_t size)
+{
+	sata_bd_dev_t *sbd = bd_srv_sata(bd);
+
+	if (size < cnt * sbd->block_size)
+		return EINVAL;
+
+	return ahci_read_blocks(sbd->sess, ba, cnt, buf);
+}
+
+/** Write blocks to partition. */
+static int sata_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
+    const void *buf, size_t size)
+{
+	sata_bd_dev_t *sbd = bd_srv_sata(bd);
+
+	if (size < cnt * sbd->block_size)
+		return EINVAL;
+
+	return ahci_write_blocks(sbd->sess, ba, cnt, (void *)buf);
+}
+
+/** Get device block size. */
+static int sata_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
+{
+	sata_bd_dev_t *sbd = bd_srv_sata(bd);
+
+	*rsize = sbd->block_size;
+	return EOK;
+}
+
+/** Get number of blocks on device. */
+static int sata_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	sata_bd_dev_t *sbd = bd_srv_sata(bd);
+
+	*rnb = sbd->blocks;
+	return EOK;
+}
+
 
 int main(int argc, char **argv)
Index: uspace/srv/bd/sata_bd/sata_bd.h
===================================================================
--- uspace/srv/bd/sata_bd/sata_bd.h	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/bd/sata_bd/sata_bd.h	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -38,21 +38,25 @@
 #define SATA_DEV_NAME_LENGTH 256
 
+#include <async.h>
+#include <bd_srv.h>
+#include <loc.h>
 #include <sys/types.h>
-#include <loc.h>
 
 /** SATA Block Device. */
 typedef struct {
-	/** Device name in device tree. */ 
-	char* dev_name; 
-	/** SATA Device name. */ 
-	char sata_dev_name[SATA_DEV_NAME_LENGTH]; 
+	/** Device name in device tree. */
+	char *dev_name;
+	/** SATA Device name. */
+	char sata_dev_name[SATA_DEV_NAME_LENGTH];
 	/** Session to device methods. */
-	async_sess_t* sess; 
+	async_sess_t *sess;
 	/** Loc service id. */
 	service_id_t service_id;
 	/** Number of blocks. */
-	uint64_t blocks; 
+	uint64_t blocks;
 	/** Size of block. */
-	size_t block_size; 
+	size_t block_size;
+	/** Block device server structure */
+	bd_srv_t bd;
 } sata_bd_dev_t;
 
Index: uspace/srv/fs/tmpfs/tmpfs_dump.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 4820360f68a1eed9c8456a1628020526342bf78a)
+++ uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 4802dd7d8d17cb02ec8f79547ffde538bb8c6736)
@@ -49,4 +49,6 @@
 #define TMPFS_COMM_SIZE		1024
 
+static uint8_t tmpfs_buf[TMPFS_COMM_SIZE];
+
 struct rdentry {
 	uint8_t type;
@@ -68,5 +70,5 @@
 		uint32_t size;
 		
-		if (block_seqread(dsid, bufpos, buflen, pos, &entry,
+		if (block_seqread(dsid, tmpfs_buf, bufpos, buflen, pos, &entry,
 		    sizeof(entry)) != EOK)
 			return false;
@@ -88,5 +90,5 @@
 			}
 			
-			if (block_seqread(dsid, bufpos, buflen, pos, fname,
+			if (block_seqread(dsid, tmpfs_buf, bufpos, buflen, pos, fname,
 			    entry.len) != EOK) {
 				(void) ops->destroy(fn);
@@ -104,5 +106,5 @@
 			free(fname);
 			
-			if (block_seqread(dsid, bufpos, buflen, pos, &size,
+			if (block_seqread(dsid, tmpfs_buf, bufpos, buflen, pos, &size,
 			    sizeof(size)) != EOK)
 				return false;
@@ -116,5 +118,5 @@
 			
 			nodep->size = size;
-			if (block_seqread(dsid, bufpos, buflen, pos, nodep->data,
+			if (block_seqread(dsid, tmpfs_buf, bufpos, buflen, pos, nodep->data,
 			    size) != EOK)
 				return false;
@@ -132,5 +134,5 @@
 			}
 			
-			if (block_seqread(dsid, bufpos, buflen, pos, fname,
+			if (block_seqread(dsid, tmpfs_buf, bufpos, buflen, pos, fname,
 			    entry.len) != EOK) {
 				(void) ops->destroy(fn);
@@ -176,5 +178,5 @@
 	
 	char tag[6];
-	if (block_seqread(dsid, &bufpos, &buflen, &pos, tag, 5) != EOK)
+	if (block_seqread(dsid, tmpfs_buf, &bufpos, &buflen, &pos, tag, 5) != EOK)
 		goto error;
 	
