Index: kernel/arch/amd64/include/cpu.h
===================================================================
--- kernel/arch/amd64/include/cpu.h	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ kernel/arch/amd64/include/cpu.h	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -36,7 +36,14 @@
 #define KERN_amd64_CPU_H_
 
-#define RFLAGS_IF  (1 << 9)
-#define RFLAGS_DF  (1 << 10)
-#define RFLAGS_RF  (1 << 16)
+#define RFLAGS_CF	(1 << 0)
+#define RFLAGS_PF	(1 << 2)
+#define RFLAGS_AF	(1 << 4)
+#define RFLAGS_ZF	(1 << 6)
+#define RFLAGS_SF	(1 << 7)
+#define RFLAGS_TF	(1 << 8)
+#define RFLAGS_IF	(1 << 9)
+#define RFLAGS_DF	(1 << 10)
+#define RFLAGS_OF	(1 << 11)
+#define RFLAGS_RF	(1 << 16)
 
 #define EFER_MSR_NUM    0xc0000080
Index: kernel/arch/amd64/src/userspace.c
===================================================================
--- kernel/arch/amd64/src/userspace.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ kernel/arch/amd64/src/userspace.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -34,4 +34,5 @@
 
 #include <userspace.h>
+#include <arch/cpu.h>
 #include <arch/pm.h>
 #include <arch/types.h>
@@ -50,29 +51,30 @@
 	ipl_t ipl = interrupts_disable();
 	
-	/* Clear CF, PF, AF, ZF, SF, DF, OF */
-	ipl &= ~(0xcd4);
+	ipl &= ~(RFLAGS_CF | RFLAGS_PF | RFLAGS_AF | RFLAGS_ZF | RFLAGS_SF |
+	    RFLAGS_DF | RFLAGS_OF);
 	
 	asm volatile (
-			"pushq %[udata_des]\n"
-			"pushq %[stack_size]\n"
-			"pushq %[ipl]\n"
-			"pushq %[utext_des]\n"
-			"pushq %[entry]\n"
-			"movq %[uarg], %%rax\n"
+		"pushq %[udata_des]\n"
+		"pushq %[stack_size]\n"
+		"pushq %[ipl]\n"
+		"pushq %[utext_des]\n"
+		"pushq %[entry]\n"
+		"movq %[uarg], %%rax\n"
 			
-			/* %rdi is defined to hold pcb_ptr - set it to 0 */
-			"xorq %%rdi, %%rdi\n"
-			"iretq\n"
-			:: [udata_des] "i" (gdtselector(UDATA_DES) | PL_USER),
-			   [stack_size] "r" (kernel_uarg->uspace_stack + THREAD_STACK_SIZE),
-			   [ipl] "r" (ipl),
-			   [utext_des] "i" (gdtselector(UTEXT_DES) | PL_USER),
-			   [entry] "r" (kernel_uarg->uspace_entry),
-			   [uarg] "r" (kernel_uarg->uspace_uarg)
-			: "rax"
-		);
+		/* %rdi is defined to hold pcb_ptr - set it to 0 */
+		"xorq %%rdi, %%rdi\n"
+		"iretq\n"
+		:: [udata_des] "i" (gdtselector(UDATA_DES) | PL_USER),
+		   [stack_size] "r" (kernel_uarg->uspace_stack + THREAD_STACK_SIZE),
+		   [ipl] "r" (ipl),
+		   [utext_des] "i" (gdtselector(UTEXT_DES) | PL_USER),
+		   [entry] "r" (kernel_uarg->uspace_entry),
+		   [uarg] "r" (kernel_uarg->uspace_uarg)
+		: "rax"
+	);
 	
 	/* Unreachable */
-	while (1);
+	while (1)
+		;
 }
 
Index: kernel/arch/sparc64/src/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sparc64.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ kernel/arch/sparc64/src/sparc64.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -135,4 +135,5 @@
 void userspace(uspace_arg_t *kernel_uarg)
 {
+	(void) interrupts_disable();
 	switch_to_userspace((uintptr_t) kernel_uarg->uspace_entry,
 	    ((uintptr_t) kernel_uarg->uspace_stack) + STACK_SIZE
Index: kernel/generic/src/ipc/event.c
===================================================================
--- kernel/generic/src/ipc/event.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ kernel/generic/src/ipc/event.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -45,9 +45,5 @@
 #include <arch.h>
 
-/**
- * The events array.
- * Arranging the events in this two-dimensional array should decrease the
- * likelyhood of cacheline ping-pong.
- */
+/** The events array. */
 static event_t events[EVENT_END];
 
Index: kernel/generic/src/main/uinit.c
===================================================================
--- kernel/generic/src/main/uinit.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ kernel/generic/src/main/uinit.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -81,11 +81,4 @@
 	free((uspace_arg_t *) arg);
 	
-	/*
-	 * Disable interrupts so that the execution of userspace() is not
-	 * disturbed by any interrupts as some of the userspace()
-	 * implementations will switch to the userspace stack before switching
-	 * the mode.
-	 */
-	(void) interrupts_disable();
 	userspace(&uarg);
 }
Index: kernel/generic/src/printf/printf_core.c
===================================================================
--- kernel/generic/src/printf/printf_core.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ kernel/generic/src/printf/printf_core.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -491,5 +491,5 @@
 		counter += retval;
 	
-	/* Print tailing spaces */
+	/* Print trailing spaces */
 	
 	while (width-- > 0) {
Index: kernel/generic/src/printf/vsnprintf.c
===================================================================
--- kernel/generic/src/printf/vsnprintf.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ kernel/generic/src/printf/vsnprintf.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -100,5 +100,5 @@
 	}
 	
-	/* Buffer is big enought to print the whole string */
+	/* Buffer is big enough to print the whole string */
 	memcpy((void *)(data->dst + data->len), (void *) str, size);
 	data->len += size;
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ kernel/generic/src/proc/task.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -75,4 +75,7 @@
 static task_id_t task_counter = 0;
 
+/* Forward declarations. */
+static void task_kill_internal(task_t *);
+
 /** Initialize kernel tasks support. */
 void task_init(void)
@@ -83,5 +86,5 @@
 
 /*
- * The idea behind this walker is to remember a single task different from
+ * The idea behind this walker is to kill and count all tasks different from
  * TASK.
  */
@@ -89,9 +92,12 @@
 {
 	task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
-	task_t **tp = (task_t **) arg;
-
-	if (t != TASK) { 
-		*tp = t;
-		return false;	/* stop walking */
+	unsigned *cnt = (unsigned *) arg;
+
+	if (t != TASK) {
+		(*cnt)++;
+#ifdef CONFIG_DEBUG
+		printf("[%"PRIu64"] ", t->taskid);
+#endif
+		task_kill_internal(t);
 	}
 
@@ -102,31 +108,22 @@
 void task_done(void)
 {
-	task_t *t;
+	unsigned tasks_left;
+
 	do { /* Repeat until there are any tasks except TASK */
-		
 		/* Messing with task structures, avoid deadlock */
+#ifdef CONFIG_DEBUG
+		printf("Killing tasks... ");
+#endif
 		ipl_t ipl = interrupts_disable();
 		spinlock_lock(&tasks_lock);
-		
-		t = NULL;
-		avltree_walk(&tasks_tree, task_done_walker, &t);
-		
-		if (t != NULL) {
-			task_id_t id = t->taskid;
-			
-			spinlock_unlock(&tasks_lock);
-			interrupts_restore(ipl);
-			
+		tasks_left = 0;
+		avltree_walk(&tasks_tree, task_done_walker, &tasks_left);
+		spinlock_unlock(&tasks_lock);
+		interrupts_restore(ipl);
+		thread_sleep(1);
 #ifdef CONFIG_DEBUG
-			printf("Killing task %" PRIu64 "\n", id);
-#endif			
-			task_kill(id);
-			thread_usleep(10000);
-		} else {
-			spinlock_unlock(&tasks_lock);
-			interrupts_restore(ipl);
-		}
-		
-	} while (t != NULL);
+		printf("\n");
+#endif
+	} while (tasks_left);
 }
 
@@ -350,31 +347,8 @@
 }
 
-/** Kill task.
- *
- * This function is idempotent.
- * It signals all the task's threads to bail it out.
- *
- * @param id		ID of the task to be killed.
- *
- * @return		Zero on success or an error code from errno.h.
- */
-int task_kill(task_id_t id)
-{
-	ipl_t ipl;
-	task_t *ta;
+static void task_kill_internal(task_t *ta)
+{
 	link_t *cur;
 
-	if (id == 1)
-		return EPERM;
-	
-	ipl = interrupts_disable();
-	spinlock_lock(&tasks_lock);
-	if (!(ta = task_find_by_id(id))) {
-		spinlock_unlock(&tasks_lock);
-		interrupts_restore(ipl);
-		return ENOENT;
-	}
-	spinlock_unlock(&tasks_lock);
-	
 	/*
 	 * Interrupt all threads.
@@ -397,6 +371,33 @@
 	}
 	spinlock_unlock(&ta->lock);
+}
+
+/** Kill task.
+ *
+ * This function is idempotent.
+ * It signals all the task's threads to bail it out.
+ *
+ * @param id		ID of the task to be killed.
+ *
+ * @return		Zero on success or an error code from errno.h.
+ */
+int task_kill(task_id_t id)
+{
+	ipl_t ipl;
+	task_t *ta;
+
+	if (id == 1)
+		return EPERM;
+	
+	ipl = interrupts_disable();
+	spinlock_lock(&tasks_lock);
+	if (!(ta = task_find_by_id(id))) {
+		spinlock_unlock(&tasks_lock);
+		interrupts_restore(ipl);
+		return ENOENT;
+	}
+	task_kill_internal(ta);
+	spinlock_unlock(&tasks_lock);
 	interrupts_restore(ipl);
-	
 	return 0;
 }
Index: tools/config.py
===================================================================
--- tools/config.py	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ tools/config.py	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -225,5 +225,5 @@
 	"Create output configuration"
 	
-	revision = commands.getoutput('svnversion . 2> /dev/null')
+	revision = commands.getoutput('bzr version-info --custom --template="{revision_id}" 2> /dev/null')
 	timestamp = commands.getoutput('date "+%Y-%m-%d %H:%M:%S"')
 	
Index: uspace/lib/libc/generic/io/printf_core.c
===================================================================
--- uspace/lib/libc/generic/io/printf_core.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ uspace/lib/libc/generic/io/printf_core.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -490,5 +490,5 @@
 		counter += retval;
 	
-	/* Print tailing spaces */
+	/* Print trailing spaces */
 	
 	while (width-- > 0) {
Index: uspace/lib/libc/generic/io/vsnprintf.c
===================================================================
--- uspace/lib/libc/generic/io/vsnprintf.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ uspace/lib/libc/generic/io/vsnprintf.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -100,5 +100,5 @@
 	}
 	
-	/* Buffer is big enought to print the whole string */
+	/* Buffer is big enough to print the whole string */
 	memcpy((void *)(data->dst + data->len), (void *) str, size);
 	data->len += size;
Index: uspace/lib/libc/generic/malloc.c
===================================================================
--- uspace/lib/libc/generic/malloc.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ uspace/lib/libc/generic/malloc.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -392,5 +392,5 @@
 		if (orig_size - real_size >= STRUCT_OVERHEAD) {
 			/* Split the original block to a full block
-			   and a tailing free block */
+			   and a trailing free block */
 			block_init((void *) head, real_size, false);
 			block_init((void *) head + real_size,
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -36,6 +36,5 @@
  *
  * This driver currently works only with CHS addressing and uses PIO.
- * Currently based on the (now obsolete) ANSI X3.221-1994 (ATA-1) standard.
- * At this point only reading is possible, not writing.
+ * Currently based on the (now obsolete) ATA-1, ATA-2 standards.
  *
  * The driver services a single controller which can have up to two disks
@@ -61,9 +60,15 @@
 #define NAME "ata_bd"
 
+/** Physical block size. Should be always 512. */
 static const size_t block_size = 512;
+
+/** Size of the communication area. */
 static size_t comm_size;
 
+/** I/O base address of the command registers. */
 static uintptr_t cmd_physical = 0x1f0;
+/** I/O base address of the control registers. */
 static uintptr_t ctl_physical = 0x170;
+
 static ata_cmd_t *cmd;
 static ata_ctl_t *ctl;
@@ -81,8 +86,9 @@
     const void *buf);
 static int drive_identify(int drive_id, disk_t *d);
+static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
+    unsigned timeout);
 
 int main(int argc, char **argv)
 {
-	uint8_t status;
 	char name[16];
 	int i, rc;
@@ -96,20 +102,17 @@
 		return -1;
 
-	/* Put drives to reset, disable interrupts. */
-	printf("Reset drives... ");
-	fflush(stdout);
-
-	pio_write_8(&ctl->device_control, DCR_SRST);
-	/* FIXME: Find out how to do this properly. */
-	async_usleep(100);
-	pio_write_8(&ctl->device_control, 0);
-
-	do {
-		status = pio_read_8(&cmd->status);
-	} while ((status & SR_BSY) != 0);
-	printf("Done\n");
-
-	(void) drive_identify(0, &disk[0]);
-	(void) drive_identify(1, &disk[1]);
+	for (i = 0; i < MAX_DISKS; i++) {
+		printf("Identify drive %d... ", i);
+		fflush(stdout);
+
+		rc = drive_identify(i, &disk[i]);
+
+		if (rc == EOK) {
+			printf("%u cylinders, %u heads, %u sectors\n",
+			    disk[i].cylinders, disk[i].heads, disk[i].sectors);
+		} else {
+			printf("Not found.\n");
+		}
+	}
 
 	n_disks = 0;
@@ -144,55 +147,6 @@
 }
 
-static int drive_identify(int disk_id, disk_t *d)
-{
-	uint16_t data;
-	uint8_t status;
-	size_t i;
-
-	printf("Identify drive %d... ", disk_id);
-	fflush(stdout);
-
-	pio_write_8(&cmd->drive_head, ((disk_id != 0) ? DHR_DRV : 0));
-	async_usleep(100);
-	pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
-
-	status = pio_read_8(&cmd->status);
-
-	d->present = false;
-
-	/*
-	 * Detect if drive is present. This is Qemu only! Need to
-	 * do the right thing to work with real drives.
-	 */
-	if ((status & SR_DRDY) == 0) {
-		printf("None attached.\n");
-		return ENOENT;
-	}
-
-	for (i = 0; i < block_size / 2; i++) {
-		do {
-			status = pio_read_8(&cmd->status);
-		} while ((status & SR_DRDY) == 0);
-
-		data = pio_read_16(&cmd->data_port);
-
-		switch (i) {
-		case 1: d->cylinders = data; break;
-		case 3: d->heads = data; break;
-		case 6: d->sectors = data; break;
-		}
-	}
-
-	d->blocks = d->cylinders * d->heads * d->sectors;
-
-	printf("Geometry: %u cylinders, %u heads, %u sectors\n",
-		d->cylinders, d->heads, d->sectors);
-
-	d->present = true;
-	fibril_mutex_initialize(&d->lock);
-
-	return EOK;
-}
-
+
+/** Register driver and enable device I/O. */
 static int ata_bd_init(void)
 {
@@ -226,4 +180,5 @@
 }
 
+/** Block device connection handler */
 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -296,4 +251,14 @@
 }
 
+/** 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)
@@ -327,5 +292,78 @@
 }
 
-
+/** Issue IDENTIFY command.
+ *
+ * This is used to detect whether an ATA device is present and if so,
+ * to determine its parameters. The parameters are written to @a d.
+ *
+ * @param disk_id	Device ID, 0 or 1.
+ * @param d		Device structure to store parameters in.
+ */
+static int drive_identify(int disk_id, disk_t *d)
+{
+	uint16_t data;
+	uint8_t status;
+	uint8_t drv_head;
+	size_t i;
+
+	drv_head = ((disk_id != 0) ? DHR_DRV : 0);
+	d->present = false;
+
+	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
+		return EIO;
+
+	pio_write_8(&cmd->drive_head, drv_head);
+
+	/*
+	 * This is where we would most likely expect a non-existing device to
+	 * show up by not setting SR_DRDY.
+	 */
+	if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
+		return EIO;
+
+	pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
+
+	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
+		return EIO;
+
+	/* Read data from the disk buffer. */
+
+	if ((status & SR_DRQ) != 0) {
+//		for (i = 0; i < block_size / 2; i++) {
+//			data = pio_read_16(&cmd->data_port);
+//			((uint16_t *) buf)[i] = data;
+//		}
+
+		for (i = 0; i < block_size / 2; i++) {
+			data = pio_read_16(&cmd->data_port);
+
+			switch (i) {
+			case 1: d->cylinders = data; break;
+			case 3: d->heads = data; break;
+			case 6: d->sectors = data; break;
+			}
+		}
+	}
+
+	if ((status & SR_ERR) != 0)
+		return EIO;
+
+	d->blocks = d->cylinders * d->heads * d->sectors;
+
+	d->present = true;
+	fibril_mutex_initialize(&d->lock);
+
+	return EOK;
+}
+
+/** Read a physical from the device.
+ *
+ * @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 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,
     void *buf)
@@ -361,21 +399,39 @@
 	/* Program a Read Sectors operation. */
 
+	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
 	pio_write_8(&cmd->drive_head, drv_head);
+
+	if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
 	pio_write_8(&cmd->sector_count, 1);
 	pio_write_8(&cmd->sector_number, s);
 	pio_write_8(&cmd->cylinder_low, c & 0xff);
 	pio_write_8(&cmd->cylinder_high, c >> 16);
+
 	pio_write_8(&cmd->command, CMD_READ_SECTORS);
 
-	/* Read data from the disk buffer. */
-
-	for (i = 0; i < block_size / 2; i++) {
-		do {
-			status = pio_read_8(&cmd->status);
-		} while ((status & SR_DRDY) == 0);
-
-		data = pio_read_16(&cmd->data_port);
-		((uint16_t *) buf)[i] = data;
-	}
+	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	if ((status & SR_DRQ) != 0) {
+		/* Read data from the device buffer. */
+
+		for (i = 0; i < block_size / 2; i++) {
+			data = pio_read_16(&cmd->data_port);
+			((uint16_t *) buf)[i] = data;
+		}
+	}
+
+	if ((status & SR_ERR) != 0)
+		return EIO;
 
 	fibril_mutex_unlock(&d->lock);
@@ -383,4 +439,13 @@
 }
 
+/** Write a physical block to the device.
+ *
+ * @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 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,
     const void *buf)
@@ -413,27 +478,98 @@
 	fibril_mutex_lock(&d->lock);
 
-	/* Program a Read Sectors operation. */
+	/* Program a Write Sectors operation. */
+
+	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
 
 	pio_write_8(&cmd->drive_head, drv_head);
+
+	if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
 	pio_write_8(&cmd->sector_count, 1);
 	pio_write_8(&cmd->sector_number, s);
 	pio_write_8(&cmd->cylinder_low, c & 0xff);
 	pio_write_8(&cmd->cylinder_high, c >> 16);
+
 	pio_write_8(&cmd->command, CMD_WRITE_SECTORS);
 
-	/* Write data to the disk buffer. */
-
-	for (i = 0; i < block_size / 2; i++) {
-		do {
-			status = pio_read_8(&cmd->status);
-		} while ((status & SR_DRDY) == 0);
-
-		pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
+	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	if ((status & SR_DRQ) != 0) {
+		/* Write data to the device buffer. */
+
+		for (i = 0; i < block_size / 2; i++) {
+			pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
+		}
 	}
 
 	fibril_mutex_unlock(&d->lock);
+
+	if (status & SR_ERR)
+		return EIO;
+
 	return EOK;
 }
 
+/** Wait until some status bits are set and some are reset.
+ *
+ * Example: wait_status(SR_DRDY, ~SR_BSY) waits for SR_DRDY to become
+ * set and SR_BSY to become reset.
+ *
+ * @param set		Combination if bits which must be all set.
+ * @param n_reset	Negated combination of bits which must be all reset.
+ * @param pstatus	Pointer where to store last read status or NULL.
+ * @param timeout	Timeout in 10ms units.
+ *
+ * @return		EOK on success, EIO on timeout.
+ */
+static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
+    unsigned timeout)
+{
+	uint8_t status;
+	int cnt;
+
+	status = pio_read_8(&cmd->status);
+
+	/*
+	 * This is crude, yet simple. First try with 1us delays
+	 * (most likely the device will respond very fast). If not,
+	 * start trying every 10 ms.
+	 */
+
+	cnt = 100;
+	while ((status & ~n_reset) != 0 || (status & set) != set) {
+		async_usleep(1);
+		--cnt;
+		if (cnt <= 0) break;
+
+		status = pio_read_8(&cmd->status);
+	}
+
+	cnt = timeout;
+	while ((status & ~n_reset) != 0 || (status & set) != set) {
+		async_usleep(10000);
+		--cnt;
+		if (cnt <= 0) break;
+
+		status = pio_read_8(&cmd->status);
+	}
+
+	if (pstatus)
+		*pstatus = status;
+
+	if (cnt == 0)
+		return EIO;
+
+	return EOK;
+}
 
 /**
Index: uspace/srv/bd/ata_bd/ata_bd.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.h	(revision cb0ea396374ac492a0af9b8eb2d2147d94ed34fd)
+++ uspace/srv/bd/ata_bd/ata_bd.h	(revision 24f27bb9d648012ca1373c369429f2803d6508ab)
@@ -135,4 +135,11 @@
 };
 
+/** Timeout definitions. Unit is 10 ms. */
+enum ata_timeout {
+	TIMEOUT_PROBE	=  100, /*  1 s */
+	TIMEOUT_BSY	=  100, /*  1 s */
+	TIMEOUT_DRDY	= 1000  /* 10 s */
+};
+
 typedef struct {
 	bool present;
