Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 95bc57cf68d3313bd1ab4ae930757d5fa26a00e5)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision cfa8738838df71dd95be3c27a20e6a58746df3be)
@@ -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);
