Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ boot/Makefile.common	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -98,4 +98,5 @@
 	$(USPACE_PATH)/srv/bd/part/guid_part/g_part \
 	$(USPACE_PATH)/srv/bd/part/mbr_part/mbr_part \
+	$(USPACE_PATH)/srv/bd/sata_bd/sata_bd \
 	$(USPACE_PATH)/srv/clipboard/clipboard \
 	$(USPACE_PATH)/srv/fs/tmpfs/tmpfs \
@@ -124,5 +125,6 @@
 	nic/ne2k \
 	nic/e1k \
-	nic/rtl8139
+	nic/rtl8139 \
+	block/ahci
 
 RD_DRV_CFG =
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ kernel/Makefile	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -196,4 +196,5 @@
 	generic/src/console/chardev.c \
 	generic/src/console/console.c \
+	generic/src/console/prompt.c \
 	generic/src/cpu/cpu.c \
 	generic/src/ddi/ddi.c \
Index: kernel/generic/include/console/prompt.h
===================================================================
--- kernel/generic/include/console/prompt.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ kernel/generic/include/console/prompt.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 genericconsole
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_CONSOLE_PROMPT_H_
+#define KERN_CONSOLE_PROMPT_H_
+
+#include <console/chardev.h>
+
+#define MAX_TAB_HINTS 37
+
+extern bool console_prompt_display_all_hints(indev_t *, size_t);
+extern bool console_prompt_more_hints(indev_t *, size_t *);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/debug.h
===================================================================
--- kernel/generic/include/debug.h	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ kernel/generic/include/debug.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -37,5 +37,5 @@
 
 #include <panic.h>
-#include <symtab.h>
+#include <symtab_lookup.h>
 
 #define CALLER  ((uintptr_t) __builtin_return_address(0))
Index: kernel/generic/include/symtab.h
===================================================================
--- kernel/generic/include/symtab.h	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ kernel/generic/include/symtab.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -36,27 +36,9 @@
 #define KERN_SYMTAB_H_
 
-#include <typedefs.h>
+#include <symtab_lookup.h>
+#include <console/chardev.h>
 
-#define MAX_SYMBOL_NAME  64
-
-struct symtab_entry {
-	uint64_t address_le;
-	char symbol_name[MAX_SYMBOL_NAME];
-};
-
-extern int symtab_name_lookup(uintptr_t, const char **, uintptr_t *);
-extern const char *symtab_fmt_name_lookup(uintptr_t);
-extern int symtab_addr_lookup(const char *, uintptr_t *);
 extern void symtab_print_search(const char *);
-extern int symtab_compl(char *, size_t);
-
-#ifdef CONFIG_SYMTAB
-
-/** Symtable linked together by build process
- *
- */
-extern struct symtab_entry symbol_table[];
-
-#endif /* CONFIG_SYMTAB */
+extern int symtab_compl(char *, size_t, indev_t *);
 
 #endif
Index: kernel/generic/include/symtab_lookup.h
===================================================================
--- kernel/generic/include/symtab_lookup.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ kernel/generic/include/symtab_lookup.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005 Ondrej Palkovsky
+ * 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 generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_SYMTAB_LOOKUP_H_
+#define KERN_SYMTAB_LOOKUP_H_
+
+#include <typedefs.h>
+
+#define MAX_SYMBOL_NAME  64
+
+struct symtab_entry {
+	uint64_t address_le;
+	char symbol_name[MAX_SYMBOL_NAME];
+};
+
+extern int symtab_name_lookup(uintptr_t, const char **, uintptr_t *);
+extern const char *symtab_fmt_name_lookup(uintptr_t);
+extern int symtab_addr_lookup(const char *, uintptr_t *);
+
+#ifdef CONFIG_SYMTAB
+
+/** Symtable linked together by build process
+ *
+ */
+extern struct symtab_entry symbol_table[];
+
+#endif /* CONFIG_SYMTAB */
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/src/console/kconsole.c
===================================================================
--- kernel/generic/src/console/kconsole.c	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ kernel/generic/src/console/kconsole.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -43,4 +43,5 @@
 #include <console/chardev.h>
 #include <console/cmd.h>
+#include <console/prompt.h>
 #include <print.h>
 #include <panic.h>
@@ -201,12 +202,23 @@
  *
  */
-NO_TRACE static int cmdtab_compl(char *input, size_t size)
+NO_TRACE static int cmdtab_compl(char *input, size_t size, indev_t *indev)
 {
 	const char *name = input;
 	
 	size_t found = 0;
+	
+	/*
+	 * Maximum Match Length: Length of longest matching common
+	 * substring in case more than one match is found.
+	 */
+	size_t max_match_len = size;
+	size_t max_match_len_tmp = size;
+	size_t input_len = str_length(input);
 	link_t *pos = NULL;
 	const char *hint;
 	char *output = malloc(MAX_CMDLINE, 0);
+	size_t hints_to_show = MAX_TAB_HINTS - 1;
+	size_t total_hints_shown = 0;
+	bool continue_showing_hints = true;
 	
 	output[0] = 0;
@@ -218,4 +230,14 @@
 		pos = pos->next;
 		found++;
+	}
+	
+	/*
+	 * If the number of possible completions is more than MAX_TAB_HINTS,
+	 * ask the user whether to display them or not.
+	 */
+	if (found > MAX_TAB_HINTS) {
+		printf("\n");
+		continue_showing_hints =
+		    console_prompt_display_all_hints(indev, found);
 	}
 	
@@ -225,7 +247,29 @@
 		while (cmdtab_search_one(name, &pos)) {
 			cmd_info_t *hlp = list_get_instance(pos, cmd_info_t, link);
-			printf("%s (%s)\n", hlp->name, hlp->description);
+			
+			if (continue_showing_hints) {
+				printf("%s (%s)\n", hlp->name, hlp->description);
+				--hints_to_show;
+				++total_hints_shown;
+				
+				if ((hints_to_show == 0) && (total_hints_shown != found)) {
+					/* Ask user to continue */
+					continue_showing_hints =
+					    console_prompt_more_hints(indev, &hints_to_show);
+				}
+			}
+			
 			pos = pos->next;
-		}
+			
+			for (max_match_len_tmp = 0;
+			    (output[max_match_len_tmp] ==
+			    hlp->name[input_len + max_match_len_tmp]) &&
+			    (max_match_len_tmp < max_match_len); ++max_match_len_tmp);
+			
+			max_match_len = max_match_len_tmp;
+		}
+		
+		/* Keep only the characters common in all completions */
+		output[max_match_len] = 0;
 	}
 	
@@ -280,6 +324,8 @@
 				continue;
 			
-			/* Find the beginning of the word
-			   and copy it to tmp */
+			/*
+			 * Find the beginning of the word
+			 * and copy it to tmp
+			 */
 			size_t beg;
 			for (beg = position - 1; (beg > 0) && (!isspace(current[beg]));
@@ -294,23 +340,17 @@
 			if (beg == 0) {
 				/* Command completion */
-				found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
+				found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev);
 			} else {
 				/* Symbol completion */
-				found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
+				found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev);
 			}
 			
 			if (found == 0)
 				continue;
-			
-			if (found > 1) {
-				/* No unique hint, list was printed */
-				printf("%s> ", prompt);
-				printf("%ls", current);
-				print_cc('\b', wstr_length(current) - position);
-				continue;
-			}
-			
-			/* We have a hint */
-			
+
+			/*
+			 * We have hints, possibly many. In case of more than one hint,
+			 * tmp will contain the common prefix.
+			 */
 			size_t off = 0;
 			size_t i = 0;
@@ -318,6 +358,18 @@
 				if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
 					break;
+				
 				i++;
 			}
+			
+			if (found > 1) {
+				/* No unique hint, list was printed */
+				printf("%s> ", prompt);
+				printf("%ls", current);
+				position += str_length(tmp);
+				print_cc('\b', wstr_length(current) - position);
+				continue;
+			}
+			
+			/* We have a hint */
 			
 			printf("%ls", current + position);
@@ -540,5 +592,5 @@
 /** Parse command line.
  *
- * @param cmdline Command line as read from input device. 
+ * @param cmdline Command line as read from input device.
  * @param size    Size (in bytes) of the string.
  *
Index: kernel/generic/src/console/prompt.c
===================================================================
--- kernel/generic/src/console/prompt.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ kernel/generic/src/console/prompt.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2012 Sandeep Kumar
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 genericconsole
+ * @{
+ */
+
+/**
+ * @file
+ * @brief Kernel console special prompts.
+ */
+
+#include <console/prompt.h>
+
+/** Display the <i>display all possibilities</i> prompt and wait for answer.
+ *
+ * @param indev Where to read characters from.
+ * @param hints Number of hints that would be displayed.
+ *
+ * @return Whether to print all hints.
+ *
+ */
+bool console_prompt_display_all_hints(indev_t *indev, size_t hints)
+{
+	ASSERT(indev);
+	ASSERT(hints > 0);
+	
+	printf("Display all %zu possibilities? (y or n) ", hints);
+	
+	while (true) {
+		wchar_t answer = indev_pop_character(indev);
+		
+		if ((answer == 'y') || (answer == 'Y')) {
+			printf("y");
+			return true;
+		}
+		
+		if ((answer == 'n') || (answer == 'N')) {
+			printf("n");
+			return false;
+		}
+	}
+}
+
+/** Display the <i>--more--</i> prompt and wait for answer.
+ *
+ * When the function returns false, @p display_hints is set to zero.
+ *
+ * @param[in]  indev         Where to read characters from.
+ * @param[out] display_hints How many hints to display.
+ *
+ * @return Whether to display more hints.
+ *
+ */
+bool console_prompt_more_hints(indev_t *indev, size_t *display_hints)
+{
+	ASSERT(indev);
+	ASSERT(display_hints != NULL);
+	
+	printf("--More--");
+	while (true) {
+		wchar_t continue_showing_hints = indev_pop_character(indev);
+		/* Display a full page again? */
+		if ((continue_showing_hints == 'y') ||
+		    (continue_showing_hints == 'Y') ||
+		    (continue_showing_hints == ' ')) {
+			*display_hints = MAX_TAB_HINTS - 1;
+			break;
+		}
+		
+		/* Stop displaying hints? */
+		if ((continue_showing_hints == 'n') ||
+		    (continue_showing_hints == 'N') ||
+		    (continue_showing_hints == 'q') ||
+		    (continue_showing_hints == 'Q')) {
+			*display_hints = 0;
+			break;
+		}
+		
+		/* Show one more hint? */
+		if (continue_showing_hints == '\n') {
+			*display_hints = 1;
+			break;
+		}
+	}
+	
+	/* Delete the --More-- option */
+	printf("\r         \r");
+	
+	return *display_hints > 0;
+}
+
+/** @}
+ */
Index: kernel/generic/src/debug/symtab.c
===================================================================
--- kernel/generic/src/debug/symtab.c	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ kernel/generic/src/debug/symtab.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -43,4 +43,5 @@
 #include <typedefs.h>
 #include <errno.h>
+#include <console/prompt.h>
 
 /** Get name of a symbol that seems most likely to correspond to address.
@@ -209,5 +210,5 @@
  *
  */
-int symtab_compl(char *input, size_t size)
+int symtab_compl(char *input, size_t size, indev_t *indev)
 {
 #ifdef CONFIG_SYMTAB
@@ -227,5 +228,22 @@
 	char output[MAX_SYMBOL_NAME];
 	
+	/*
+	 * Maximum Match Length: Length of longest matching common substring in
+	 * case more than one match is found.
+	 */
+	size_t max_match_len = size;
+	size_t max_match_len_tmp = size;
+	size_t input_len = str_length(input);
+	char *sym_name;
+	size_t hints_to_show = MAX_TAB_HINTS - 1;
+	size_t total_hints_shown = 0;
+	bool continue_showing_hints = true;
+	
 	output[0] = 0;
+	
+	while ((hint = symtab_search_one(name, &pos)))
+		pos++;
+	
+	pos = 0;
 	
 	while ((hint = symtab_search_one(name, &pos))) {
@@ -235,4 +253,14 @@
 		pos++;
 		found++;
+	}
+	
+	/*
+	 * If the number of possible completions is more than MAX_TAB_HINTS,
+	 * ask the user whether to display them or not.
+	 */
+	if (found > MAX_TAB_HINTS) {
+		printf("\n");
+		continue_showing_hints =
+		    console_prompt_display_all_hints(indev, found);
 	}
 	
@@ -241,7 +269,30 @@
 		pos = 0;
 		while (symtab_search_one(name, &pos)) {
-			printf("%s\n", symbol_table[pos].symbol_name);
+			sym_name = symbol_table[pos].symbol_name;
 			pos++;
+			
+			if (continue_showing_hints) {
+				/* We are still showing hints */
+				printf("%s\n", sym_name);
+				--hints_to_show;
+				++total_hints_shown;
+				
+				if ((hints_to_show == 0) && (total_hints_shown != found)) {
+					/* Ask the user to continue */
+					continue_showing_hints =
+					    console_prompt_more_hints(indev, &hints_to_show);
+				}
+			}
+			
+			for (max_match_len_tmp = 0;
+			    (output[max_match_len_tmp] ==
+			    sym_name[input_len + max_match_len_tmp]) &&
+			    (max_match_len_tmp < max_match_len); ++max_match_len_tmp);
+			
+			max_match_len = max_match_len_tmp;
 		}
+		
+		/* Keep only the characters common in all completions */
+		output[max_match_len] = 0;
 	}
 	
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ uspace/Makefile	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -89,4 +89,5 @@
 	srv/vfs \
 	srv/bd/ata_bd \
+	srv/bd/sata_bd \
 	srv/bd/file_bd \
 	srv/bd/gxe_bd \
@@ -110,4 +111,5 @@
 	drv/infrastructure/root \
 	drv/infrastructure/rootvirt \
+	drv/block/ahci \
 	drv/char/i8042 \
 	drv/char/ps2mouse \
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -62,4 +62,5 @@
 static sysarg_t console_rows = 0;
 static bool should_quit = false;
+static bool dash_represents_stdin = false;
 
 static console_ctrl_t *console = NULL;
@@ -73,4 +74,5 @@
 	{ "more", no_argument, 0, 'm' },
 	{ "hex", no_argument, 0, 'x' },
+	{ "stdin", no_argument, 0, 's' },
 	{ 0, 0, 0, 0 }
 };
@@ -93,4 +95,5 @@
 		"  -m, --more       Pause after each screen full\n"
 		"  -x, --hex        Print bytes as hex values\n"
+		"  -s  --stdin      Treat `-' in file list as standard input\n"
 		"Currently, %s is under development, some options don't work.\n",
 		cmdname, cmdname);
@@ -172,5 +175,13 @@
 	off64_t file_size = 0, length = 0;
 
-	fd = open(fname, O_RDONLY);
+	bool reading_stdin = dash_represents_stdin && (str_cmp(fname, "-") == 0);
+	
+	if (reading_stdin) {
+		fd = fileno(stdin);
+		/* Allow storing the whole UTF-8 character. */
+		blen = STR_BOUNDS(1);
+	} else
+		fd = open(fname, O_RDONLY);
+	
 	if (fd < 0) {
 		printf("Unable to open %s\n", fname);
@@ -207,8 +218,17 @@
 
 	do {
-		bytes = read(fd, buff + copied_bytes, (
-			(length != CAT_FULL_FILE && length - (off64_t)count <= (off64_t)(blen - copied_bytes)) ?
-			(size_t)(length - count) :
-			(blen - copied_bytes) ) );
+		size_t bytes_to_read;
+		if (reading_stdin) {
+			bytes_to_read = 1;
+		} else {
+			if ((length != CAT_FULL_FILE) &&
+			    (length - (off64_t)count <= (off64_t)(blen - copied_bytes))) {
+				bytes_to_read = (size_t) (length - count);
+			} else {
+				bytes_to_read = blen - copied_bytes;
+			}
+		}
+		
+		bytes = read(fd, buff + copied_bytes, bytes_to_read);
 		bytes += copied_bytes;
 		copied_bytes = 0;
@@ -242,4 +262,7 @@
 			reads++;
 		}
+		
+		if (reading_stdin)
+			fflush(stdout);
 	} while (bytes > 0 && !should_quit && (count < length || length == CAT_FULL_FILE));
 
@@ -284,5 +307,5 @@
 
 	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
-		c = getopt_long(argc, argv, "xhvmH:t:b:", long_options, &opt_ind);
+		c = getopt_long(argc, argv, "xhvmH:t:b:s", long_options, &opt_ind);
 		switch (c) {
 		case 'h':
@@ -318,4 +341,7 @@
 			hex = true;
 			break;
+		case 's':
+			dash_represents_stdin = true;
+			break;
 		}
 	}
Index: uspace/drv/block/ahci/Makefile
===================================================================
--- uspace/drv/block/ahci/Makefile	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/drv/block/ahci/Makefile	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2012 Petr Jerman
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = ahci
+
+SOURCES = \
+	ahci.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/block/ahci/ahci.c
===================================================================
--- uspace/drv/block/ahci/ahci.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/drv/block/ahci/ahci.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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.
+ */
+
+/** @file
+ * AHCI SATA driver implementation.
+ */
+
+#include <as.h>
+#include <errno.h>
+#include <stdio.h>
+#include <devman.h>
+#include <ddf/interrupt.h>
+#include <ddf/log.h>
+#include <device/hw_res_parsed.h>
+#include <device/pci.h>
+#include <sysinfo.h>
+#include <ipc/irc.h>
+#include <ns.h>
+#include <ahci_iface.h>
+#include "ahci.h"
+#include "ahci_hw.h"
+#include "ahci_sata.h"
+
+#define NAME  "ahci"
+
+#define AHCI_TIMER_TICKS  1000000000
+
+#define LO(ptr) \
+	((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff))
+
+#define HI(ptr) \
+	((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) >> 32))
+
+static int ahci_get_sata_device_name(ddf_fun_t *, size_t, char *);
+static int ahci_get_num_blocks(ddf_fun_t *, uint64_t *);
+static int ahci_get_block_size(ddf_fun_t *, size_t *);
+static int ahci_read_blocks(ddf_fun_t *, uint64_t, size_t, void *);
+static int ahci_write_blocks(ddf_fun_t *, uint64_t, size_t, void *);
+
+static int ahci_identify_device(sata_dev_t *);
+static int ahci_set_highest_ultra_dma_mode(sata_dev_t *);
+static int ahci_rb_fpdma(sata_dev_t *, void *, uint64_t);
+static int ahci_wb_fpdma(sata_dev_t *, void *, uint64_t);
+
+static void ahci_sata_devices_create(ahci_dev_t *, ddf_dev_t *);
+static ahci_dev_t *ahci_ahci_create(ddf_dev_t *);
+static void ahci_ahci_init(ahci_dev_t *);
+
+static int ahci_dev_add(ddf_dev_t *);
+
+static void ahci_get_model_name(uint16_t *, char *);
+static int ahci_pciintel_enable_interrupt(int);
+
+static fibril_mutex_t sata_devices_count_lock;
+static int sata_devices_count = 0;
+
+/*----------------------------------------------------------------------------*/
+/*-- AHCI Interface ----------------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
+
+static ahci_iface_t ahci_interface = {
+	.get_sata_device_name = &ahci_get_sata_device_name,
+	.get_num_blocks = &ahci_get_num_blocks,
+	.get_block_size = &ahci_get_block_size,
+	.read_blocks = &ahci_read_blocks,
+	.write_blocks = &ahci_write_blocks
+};
+
+static ddf_dev_ops_t ahci_ops = {
+	.interfaces[AHCI_DEV_IFACE] = &ahci_interface
+};
+
+static driver_ops_t driver_ops = {
+	.dev_add = &ahci_dev_add
+};
+
+static driver_t ahci_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+static int ahci_get_sata_device_name(ddf_fun_t *fun,
+    size_t sata_dev_name_length, char *sata_dev_name)
+{
+	sata_dev_t *sata = (sata_dev_t *) fun->driver_data;
+	str_cpy(sata_dev_name, sata_dev_name_length, sata->model);
+	return EOK;
+}
+
+static int ahci_get_num_blocks(ddf_fun_t *fun, uint64_t *num_blocks)
+{
+	sata_dev_t *sata = (sata_dev_t *) fun->driver_data;
+	*num_blocks = sata->blocks;
+	return EOK;
+}
+
+static int ahci_get_block_size(ddf_fun_t *fun, size_t *block_size)
+{
+	sata_dev_t *sata = (sata_dev_t *) fun->driver_data;
+	*block_size = sata->block_size;
+	return EOK;
+}
+
+static int ahci_read_blocks(ddf_fun_t *fun, uint64_t blocknum,
+    size_t count, void *buf)
+{
+	int rc = EOK;
+	sata_dev_t *sata = (sata_dev_t *) fun->driver_data;
+	
+	void *phys;
+	void *ibuf;
+	
+	dmamem_map_anonymous(sata->block_size, AS_AREA_READ | AS_AREA_WRITE,
+	    0, &phys, (void **) &ibuf);
+	bzero(buf, sata->block_size);
+	
+	fibril_mutex_lock(&sata->lock);
+	
+	for (size_t cur = 0; cur < count; cur++) {
+		rc = ahci_rb_fpdma(sata, phys, blocknum + cur);
+		if (rc != EOK)
+			break;
+		
+		memcpy((void *) (((uint8_t *) buf) + (sata->block_size * cur)),
+		    ibuf, sata->block_size);
+	}
+	
+	fibril_mutex_unlock(&sata->lock);
+	dmamem_unmap_anonymous(ibuf);
+	
+	return rc;
+}
+
+static int ahci_write_blocks(ddf_fun_t *fun, uint64_t blocknum,
+    size_t count, void *buf)
+{
+	int rc = EOK;
+	sata_dev_t *sata = (sata_dev_t *) fun->driver_data;
+	
+	void *phys;
+	void *ibuf;
+	
+	dmamem_map_anonymous(sata->block_size, AS_AREA_READ | AS_AREA_WRITE,
+	    0, &phys, (void **) &ibuf);
+	
+	fibril_mutex_lock(&sata->lock);
+	
+	for (size_t cur = 0; cur < count; cur++) {
+		memcpy(ibuf, (void *) (((uint8_t *) buf) + (sata->block_size * cur)),
+		    sata->block_size);
+		rc = ahci_wb_fpdma(sata, phys, blocknum + cur);
+		if (rc != EOK)
+			break;
+	}
+	
+	fibril_mutex_unlock(&sata->lock);
+	dmamem_unmap_anonymous(ibuf);
+	return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+/*-- AHCI Commands -----------------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
+
+static void ahci_identify_device_cmd(sata_dev_t *sata, void *phys)
+{
+	volatile std_command_frame_t *cmd =
+	    (std_command_frame_t *) sata->cmd_table;
+	
+	cmd->fis_type = 0x27;
+	cmd->c = 0x80;
+	cmd->command = 0xec;
+	cmd->features = 0;
+	cmd->lba_lower = 0;
+	cmd->device = 0;
+	cmd->lba_upper = 0;
+	cmd->features_upper = 0;
+	cmd->count = 0;
+	cmd->reserved1 = 0;
+	cmd->control = 0;
+	cmd->reserved2 = 0;
+	
+	volatile ahci_cmd_prdt_t *prdt =
+	    (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
+	
+	prdt->data_address_low = LO(phys);
+	prdt->data_address_upper = HI(phys);
+	prdt->reserved1 = 0;
+	prdt->dbc = 511;
+	prdt->reserved2 = 0;
+	prdt->ioc = 0;
+	
+	sata->cmd_header->prdtl = 1;
+	sata->cmd_header->flags = 0x402;
+	sata->cmd_header->bytesprocessed = 0;
+	
+	sata->port->pxsact |= 1;
+	sata->port->pxci |= 1;
+}
+
+static void ahci_identify_packet_device_cmd(sata_dev_t *sata, void *phys)
+{
+	volatile std_command_frame_t *cmd =
+	    (std_command_frame_t *) sata->cmd_table;
+	
+	cmd->fis_type = 0x27;
+	cmd->c = 0x80;
+	cmd->command = 0xa1;
+	cmd->features = 0;
+	cmd->lba_lower = 0;
+	cmd->device = 0;
+	cmd->lba_upper = 0;
+	cmd->features_upper = 0;
+	cmd->count = 0;
+	cmd->reserved1 = 0;
+	cmd->control = 0;
+	cmd->reserved2 = 0;
+	
+	volatile ahci_cmd_prdt_t *prdt =
+	    (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
+	
+	prdt->data_address_low = LO(phys);
+	prdt->data_address_upper = HI(phys);
+	prdt->reserved1 = 0;
+	prdt->dbc = 511;
+	prdt->reserved2 = 0;
+	prdt->ioc = 0;
+	
+	sata->cmd_header->prdtl = 1;
+	sata->cmd_header->flags = 0x402;
+	sata->cmd_header->bytesprocessed = 0;
+	
+	sata->port->pxsact |= 1;
+	sata->port->pxci |= 1;
+}
+
+static int ahci_identify_device(sata_dev_t *sata)
+{
+	if (sata->invalid_device) {
+		ddf_msg(LVL_ERROR,
+		    "Identify command device on invalid device");
+		return EINTR;
+	}
+	
+	void *phys;
+	identify_data_t *idata;
+	
+	dmamem_map_anonymous(512, AS_AREA_READ | AS_AREA_WRITE, 0, &phys,
+	    (void **) &idata);
+	bzero(idata, 512);
+	
+	fibril_mutex_lock(&sata->lock);
+	
+	ahci_identify_device_cmd(sata, phys);
+	
+	fibril_mutex_lock(&sata->event_lock);
+	fibril_condvar_wait(&sata->event_condvar, &sata->event_lock);
+	fibril_mutex_unlock(&sata->event_lock);
+	
+	ahci_port_is_t pxis = sata->shadow_pxis;
+	sata->shadow_pxis.u32 &= ~pxis.u32;
+	
+	if (sata->invalid_device) {
+		ddf_msg(LVL_ERROR,
+		    "Unrecoverable error during ata identify device");
+		goto error;
+	}
+	
+	if (ahci_port_is_tfes(pxis)) {
+		ahci_identify_packet_device_cmd(sata, phys);
+		
+		fibril_mutex_lock(&sata->event_lock);
+		fibril_condvar_wait(&sata->event_condvar, &sata->event_lock);
+		fibril_mutex_unlock(&sata->event_lock);
+		
+		pxis = sata->shadow_pxis;
+		sata->shadow_pxis.u32 &= ~pxis.u32;
+		
+		if ((sata->invalid_device) || (ahci_port_is_error(pxis))) {
+			ddf_msg(LVL_ERROR,
+			    "Unrecoverable error during ata identify packet device");
+			goto error;
+		}
+		
+		sata->packet_device = true;
+	} else
+		sata->packet_device = false;
+	
+	ahci_get_model_name(idata->model_name, sata->model);
+	
+	/*
+	 * Due to QEMU limitation (as of 2012-06-22),
+	 * only NCQ FPDMA mode is supported.
+	 */
+	if ((idata->sata_cap & np_cap_ncq) == 0) {
+		ddf_msg(LVL_ERROR, "%s: NCQ must be supported", sata->model);
+		goto error;
+	}
+	
+	if (sata->packet_device) {
+		/*
+		 * Due to QEMU limitation (as of 2012-06-22),
+		 * only NCQ FPDMA mode supported - block size is 512 B,
+		 * not 2048 B!
+		 */
+		sata->block_size = 512;
+		sata->blocks = 0;
+	} else {
+		sata->block_size = 512;
+		
+		if ((idata->caps & rd_cap_lba) == 0) {
+			ddf_msg(LVL_ERROR, "%s: LBA for NCQ must be supported",
+			    sata->model);
+			goto error;
+		} else if ((idata->cmd_set1 & cs1_addr48) == 0) {
+			sata->blocks = (uint32_t) idata->total_lba28_0 |
+			    ((uint32_t) idata->total_lba28_1 << 16);
+		} else {
+			/* Device supports LBA-48 addressing. */
+			sata->blocks = (uint64_t) idata->total_lba48_0 |
+			    ((uint64_t) idata->total_lba48_1 << 16) |
+			    ((uint64_t) idata->total_lba48_2 << 32) |
+			    ((uint64_t) idata->total_lba48_3 << 48);
+		}
+	}
+	
+	uint8_t udma_mask = idata->udma & 0x007f;
+	if (udma_mask == 0) {
+		ddf_msg(LVL_ERROR,
+		    "%s: UDMA mode for NCQ FPDMA mode must be supported",
+		    sata->model);
+		goto error;
+	} else {
+		for (unsigned int i = 0; i < 7; i++) {
+			if (udma_mask & (1 << i))
+				sata->highest_udma_mode = i;
+		}
+	}
+	
+	fibril_mutex_unlock(&sata->lock);
+	dmamem_unmap_anonymous(idata);
+	
+	return EOK;
+	
+error:
+	fibril_mutex_unlock(&sata->lock);
+	dmamem_unmap_anonymous(idata);
+	
+	return EINTR;
+}
+
+static void ahci_set_mode_cmd(sata_dev_t *sata, void* phys, uint8_t mode)
+{
+	volatile std_command_frame_t *cmd =
+	    (std_command_frame_t *) sata->cmd_table;
+	
+	cmd->fis_type = 0x27;
+	cmd->c = 0x80;
+	cmd->command = 0xef;
+	cmd->features = 0x03;
+	cmd->lba_lower = 0;
+	cmd->device = 0;
+	cmd->lba_upper = 0;
+	cmd->features_upper = 0;
+	cmd->count = mode;
+	cmd->reserved1 = 0;
+	cmd->control = 0;
+	cmd->reserved2 = 0;
+	
+	volatile ahci_cmd_prdt_t* prdt =
+	    (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
+	
+	prdt->data_address_low = LO(phys);
+	prdt->data_address_upper = HI(phys);
+	prdt->reserved1 = 0;
+	prdt->dbc = 511;
+	prdt->reserved2 = 0;
+	prdt->ioc = 0;
+	
+	sata->cmd_header->prdtl = 1;
+	sata->cmd_header->flags = 0x402;
+	sata->cmd_header->bytesprocessed = 0;
+	
+	sata->port->pxsact |= 1;
+	sata->port->pxci |= 1;
+}
+
+static int ahci_set_highest_ultra_dma_mode(sata_dev_t *sata)
+{
+	if (sata->invalid_device) {
+		ddf_msg(LVL_ERROR,
+		    "%s: Setting highest UDMA mode on invalid device",
+		    sata->model);
+		return EINTR;
+	}
+	
+	void *phys;
+	identify_data_t *idata;
+	
+	dmamem_map_anonymous(512, AS_AREA_READ | AS_AREA_WRITE, 0, &phys,
+	    (void **) &idata);
+	bzero(idata, 512);
+	
+	fibril_mutex_lock(&sata->lock);
+	
+	uint8_t mode = 0x40 | (sata->highest_udma_mode & 0x07);
+	ahci_set_mode_cmd(sata, phys, mode);
+	
+	fibril_mutex_lock(&sata->event_lock);
+	fibril_condvar_wait(&sata->event_condvar, &sata->event_lock);
+	fibril_mutex_unlock(&sata->event_lock);
+	
+	ahci_port_is_t pxis = sata->shadow_pxis;
+	sata->shadow_pxis.u32 &= ~pxis.u32;
+	
+	if (sata->invalid_device) {
+		ddf_msg(LVL_ERROR,
+		    "%s: Unrecoverable error during set highest UDMA mode",
+		    sata->model);
+		goto error;
+	}
+	
+	if (ahci_port_is_error(pxis)) {
+		ddf_msg(LVL_ERROR,
+		    "%s: Error during set highest UDMA mode", sata->model);
+		goto error;
+	}
+	
+	fibril_mutex_unlock(&sata->lock);
+	dmamem_unmap_anonymous(idata);
+	
+	return EOK;
+	
+error:
+	fibril_mutex_unlock(&sata->lock);
+	dmamem_unmap_anonymous(idata);
+	
+	return EINTR;
+}
+
+static void ahci_rb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum)
+{
+	volatile ncq_command_frame_t *cmd =
+	    (ncq_command_frame_t *) sata->cmd_table;
+	
+	cmd->fis_type = 0x27;
+	cmd->c = 0x80;
+	cmd->command = 0x60;
+	cmd->tag = 0;
+	cmd->control = 0;
+	
+	cmd->reserved1 = 0;
+	cmd->reserved2 = 0;
+	cmd->reserved3 = 0;
+	cmd->reserved4 = 0;
+	cmd->reserved5 = 0;
+	cmd->reserved6 = 0;
+	
+	cmd->sector_count_low = 1;
+	cmd->sector_count_high = 0;
+	
+	cmd->lba0 = blocknum & 0xff;
+	cmd->lba1 = (blocknum >> 8) & 0xff;
+	cmd->lba2 = (blocknum >> 16) & 0xff;
+	cmd->lba3 = (blocknum >> 24) & 0xff;
+	cmd->lba4 = (blocknum >> 32) & 0xff;
+	cmd->lba5 = (blocknum >> 40) & 0xff;
+	
+	volatile ahci_cmd_prdt_t *prdt =
+	    (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
+	
+	prdt->data_address_low = LO(phys);
+	prdt->data_address_upper = HI(phys);
+	prdt->reserved1 = 0;
+	prdt->dbc = sata->block_size - 1;
+	prdt->reserved2 = 0;
+	prdt->ioc = 0;
+	
+	sata->cmd_header->prdtl = 1;
+	sata->cmd_header->flags = 0x405;
+	sata->cmd_header->bytesprocessed = 0;
+	
+	sata->port->pxsact |= 1;
+	sata->port->pxci |= 1;
+}
+
+static int ahci_rb_fpdma(sata_dev_t *sata, void *phys, uint64_t blocknum)
+{
+	if (sata->invalid_device) {
+		ddf_msg(LVL_ERROR,
+		    "%s: FPDMA read from invalid device", sata->model);
+		return EINTR;
+	}
+	
+	ahci_rb_fpdma_cmd(sata, phys, blocknum);
+	
+	fibril_mutex_lock(&sata->event_lock);
+	fibril_condvar_wait(&sata->event_condvar, &sata->event_lock);
+	fibril_mutex_unlock(&sata->event_lock);
+	
+	ahci_port_is_t pxis = sata->shadow_pxis;
+	sata->shadow_pxis.u32 &= ~pxis.u32;
+	
+	if ((sata->invalid_device) || (ahci_port_is_error(pxis))) {
+		ddf_msg(LVL_ERROR,
+		    "%s: Unrecoverable error during FPDMA read", sata->model);
+		return EINTR;
+	}
+	
+	return EOK;
+}
+
+static void ahci_wb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum)
+{
+	volatile ncq_command_frame_t *cmd =
+	    (ncq_command_frame_t *) sata->cmd_table;
+	
+	cmd->fis_type = 0x27;
+	cmd->c = 0x80;
+	cmd->command = 0x61;
+	cmd->tag = 0;
+	cmd->control = 0;
+	
+	cmd->reserved1 = 0;
+	cmd->reserved2 = 0;
+	cmd->reserved3 = 0;
+	cmd->reserved4 = 0;
+	cmd->reserved5 = 0;
+	cmd->reserved6 = 0;
+	
+	cmd->sector_count_low = 1;
+	cmd->sector_count_high = 0;
+	
+	cmd->lba0 = blocknum & 0xff;
+	cmd->lba1 = (blocknum >> 8) & 0xff;
+	cmd->lba2 = (blocknum >> 16) & 0xff;
+	cmd->lba3 = (blocknum >> 24) & 0xff;
+	cmd->lba4 = (blocknum >> 32) & 0xff;
+	cmd->lba5 = (blocknum >> 40) & 0xff;
+	
+	volatile ahci_cmd_prdt_t * prdt =
+	    (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
+	
+	prdt->data_address_low = LO(phys);
+	prdt->data_address_upper = HI(phys);
+	prdt->reserved1 = 0;
+	prdt->dbc = sata->block_size - 1;
+	prdt->reserved2 = 0;
+	prdt->ioc = 0;
+	
+	sata->cmd_header->prdtl = 1;
+	sata->cmd_header->flags = 0x445;
+	sata->cmd_header->bytesprocessed = 0;
+	
+	sata->port->pxsact |= 1;
+	sata->port->pxci |= 1;
+}
+
+static int ahci_wb_fpdma(sata_dev_t *sata, void *phys, uint64_t blocknum)
+{
+	if (sata->invalid_device) {
+		ddf_msg(LVL_ERROR,
+		    "%s: FPDMA write to invalid device", sata->model);
+		return EINTR;
+	}
+	
+	ahci_wb_fpdma_cmd(sata, phys, blocknum);
+	
+	fibril_mutex_lock(&sata->event_lock);
+	fibril_condvar_wait(&sata->event_condvar, &sata->event_lock);
+	fibril_mutex_unlock(&sata->event_lock);
+	
+	ahci_port_is_t pxis = sata->shadow_pxis;
+	sata->shadow_pxis.u32 &= ~pxis.u32;
+	
+	if ((sata->invalid_device) || (ahci_port_is_error(pxis))) {
+		ddf_msg(LVL_ERROR,
+		    "%s: Unrecoverable error during FPDMA write", sata->model);
+		return EINTR;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*-- Interrupts and timer unified handling -----------------------------------*/
+/*----------------------------------------------------------------------------*/
+
+static irq_pio_range_t ahci_ranges[] = {
+	{
+		.base = 0,
+		.size = 32,
+	}
+};
+
+static irq_cmd_t ahci_cmds[] = {
+	{
+		/* Disable interrupt - interrupt is deasserted in qemu 1.0.1 */
+		.cmd = CMD_PIO_WRITE_32,
+		.addr = NULL,
+		.value = AHCI_GHC_GHC_AE
+	},
+	{
+		.cmd = CMD_PIO_READ_32,
+		.addr = NULL,
+		.dstarg = 1
+	},
+	{
+		/* Clear interrupt status register - for vbox and real hw */
+		.cmd = CMD_PIO_WRITE_A_32,
+		.addr = NULL,
+		.srcarg = 1
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+/** Unified AHCI interrupt and timer interrupt handler.
+ *
+ * @param ahci     AHCI device.
+ * @param is_timer Indicate timer interrupt.
+ *
+ */
+static void ahci_interrupt_or_timer(ahci_dev_t *ahci, bool is_timer)
+{
+	/*
+	 * Get current value of hardware interrupt state register,
+	 * clear hardware register (write to clear behavior).
+	 */
+	ahci_ghc_is_t is;
+	
+	is.u32 = ahci->memregs->ghc.is;
+	ahci->memregs->ghc.is = is.u32;
+	is.u32 = ahci->memregs->ghc.is;
+	
+	uint32_t port_event_flags = 0;
+	uint32_t port_mask = 1;
+	for (unsigned int i = 0; i < 32; i++) {
+		/*
+		 * Get current value of hardware port interrupt state register,
+		 * clear hardware register (write to clear behavior).
+		 */
+		ahci_port_is_t pxis;
+		
+		pxis.u32 = ahci->memregs->ports[i].pxis;
+		ahci->memregs->ports[i].pxis = pxis.u32;
+		
+		sata_dev_t *sata = (sata_dev_t *) ahci->sata_devs[i];
+		if (sata != NULL) {
+			/* add value to shadow copy of port interrupt state register. */
+			sata->shadow_pxis.u32 |= pxis.u32;
+			
+			/* Evaluate port event. */
+			if ((ahci_port_is_end_of_operation(pxis)) ||
+			    (ahci_port_is_error(pxis)))
+				port_event_flags |= port_mask;
+			
+			if (ahci_port_is_permanent_error(pxis))
+				sata->invalid_device = true;
+		}
+		
+		port_mask <<= 1;
+	}
+	
+	port_mask = 1;
+	for (unsigned int i = 0; i < 32; i++) {
+		sata_dev_t *sata = (sata_dev_t *) ahci->sata_devs[i];
+		if ((port_event_flags & port_mask) && (sata != NULL)) {
+			fibril_mutex_lock(&sata->event_lock);
+			fibril_condvar_signal(&sata->event_condvar);
+			fibril_mutex_unlock(&sata->event_lock);
+		}
+		
+		port_mask <<= 1;
+	}
+}
+
+/** AHCI timer interrupt handler.
+ *
+ * @param arg Pointer to AHCI device.
+ *
+ */
+static void ahci_timer(void *arg)
+{
+	ahci_dev_t *ahci = (ahci_dev_t *) arg;
+	
+	ahci_interrupt_or_timer(ahci, 1);
+	fibril_timer_set(ahci->timer, AHCI_TIMER_TICKS, ahci_timer, ahci);
+}
+
+/** AHCI interrupt handler.
+ *
+ * @param dev Pointer to device driver handler.
+ *
+ */
+static void ahci_interrupt(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *icall)
+{
+	ahci_dev_t *ahci = (ahci_dev_t *) dev->driver_data;
+	
+	ahci_interrupt_or_timer(ahci, 0);
+	
+	/* Enable interrupt. */
+	ahci->memregs->ghc.ghc |= 2;
+}
+
+/*----------------------------------------------------------------------------*/
+/*-- AHCI and SATA device creating and initializing routines -----------------*/
+/*----------------------------------------------------------------------------*/
+
+static sata_dev_t *ahci_sata_device_allocate(volatile ahci_port_t *port)
+{
+	size_t size = 4096;
+	void* phys = NULL;
+	void* virt_fb = NULL;
+	void* virt_cmd = NULL;
+	void* virt_table = NULL;
+	
+	sata_dev_t *sata = malloc(sizeof(sata_dev_t));
+	if (sata == NULL)
+		return NULL;
+	
+	bzero(sata, sizeof(sata_dev_t));
+	
+	sata->port = port;
+	
+	/* Allocate and init retfis structure. */
+	int rc = dmamem_map_anonymous(size, AS_AREA_READ | AS_AREA_WRITE, 0,
+	    &phys, &virt_fb);
+	if (rc != EOK)
+		goto error_retfis;
+	
+	bzero(virt_fb, size);
+	sata->port->pxfbu = HI(phys);
+	sata->port->pxfb = LO(phys);
+	
+	/* Allocate and init command header structure. */
+	rc = dmamem_map_anonymous(size, AS_AREA_READ | AS_AREA_WRITE, 0,
+	    &phys, &virt_cmd);
+	
+	if (rc != EOK)
+		goto error_cmd;
+	
+	bzero(virt_cmd, size);
+	sata->port->pxclbu = HI(phys);
+	sata->port->pxclb = LO(phys);
+	sata->cmd_header = (ahci_cmdhdr_t *) virt_cmd;
+	
+	/* Allocate and init command table structure. */
+	rc = dmamem_map_anonymous(size, AS_AREA_READ | AS_AREA_WRITE, 0,
+	    &phys, &virt_table);
+	
+	if (rc != EOK)
+		goto error_table;
+	
+	bzero(virt_table, size);
+	sata->cmd_header->cmdtableu = HI(phys);
+	sata->cmd_header->cmdtable = LO(phys);
+	sata->cmd_table = (uint32_t*) virt_table;
+	
+	return sata;
+	
+error_table:
+	dmamem_unmap(virt_cmd, size);
+error_cmd:
+	dmamem_unmap(virt_fb, size);
+error_retfis:
+	free(sata);
+	return NULL;
+	
+	/*
+	 * Deleting of pointers in memory hardware mapped register
+	 * unneccessary, hardware port is not in operational state.
+	 */
+}
+
+static int ahci_sata_device_create(ahci_dev_t *ahci, ddf_dev_t *dev,
+    volatile ahci_port_t *port, unsigned int port_num)
+{
+	ddf_fun_t *fun = NULL;
+	sata_dev_t *sata = ahci_sata_device_allocate(port);
+	
+	if (sata == NULL)
+		return EINTR;
+	
+	/* Set pointers between SATA and AHCI structures. */
+	sata->ahci = ahci;
+	sata->port_num = port_num;
+	ahci->sata_devs[port_num] = sata;
+	
+	fibril_mutex_initialize(&sata->lock);
+	fibril_mutex_initialize(&sata->event_lock);
+	fibril_condvar_initialize(&sata->event_condvar);
+	
+	/* Initialize SATA port operational registers. */
+	sata->port->pxis = 0;
+	sata->port->pxie = 0xffffffff;
+	sata->port->pxserr = 0;
+	sata->port->pxcmd |= 0x10;
+	sata->port->pxcmd |= 0x01;
+	
+	if (ahci_identify_device(sata) != EOK)
+		goto error;
+	
+	if (ahci_set_highest_ultra_dma_mode(sata) != EOK)
+		goto error;
+	
+	/* Add sata device to system. */
+	char sata_dev_name[1024];
+	snprintf(sata_dev_name, 1024, "ahci_%u", sata_devices_count);
+	
+	fibril_mutex_lock(&sata_devices_count_lock);
+	sata_devices_count++;
+	fibril_mutex_unlock(&sata_devices_count_lock);
+	
+	fun = ddf_fun_create(dev, fun_exposed, sata_dev_name);
+	if (fun == NULL) {
+		ddf_msg(LVL_ERROR, "Failed creating function.");
+		goto error;
+	}
+	
+	fun->ops = &ahci_ops;
+	fun->driver_data = sata;
+	int rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function.");
+		goto error;
+	}
+	
+	return EOK;
+	
+error:
+	sata->invalid_device = true;
+	if (fun != NULL)
+		ddf_fun_destroy(fun);
+	
+	return EINTR;
+}
+
+static void ahci_sata_devices_create(ahci_dev_t *ahci, ddf_dev_t *dev)
+{
+	for (unsigned int port_num = 0; port_num < 32; port_num++) {
+		/* Active ports only */
+		if (!(ahci->memregs->ghc.pi & (1 << port_num)))
+			continue;
+		
+		volatile ahci_port_t *port = ahci->memregs->ports + port_num;
+		
+		/* Active devices only */
+		if ((port->pxssts & 0x0f) != 3)
+			continue;
+		
+		ahci_sata_device_create(ahci, dev, port, port_num);
+	}
+}
+
+static ahci_dev_t *ahci_ahci_create(ddf_dev_t *dev)
+{
+	ahci_dev_t *ahci = malloc(sizeof(ahci_dev_t));
+	if (!ahci)
+		return NULL;
+	
+	bzero(ahci, sizeof(ahci_dev_t));
+	
+	ahci->dev = dev;
+	
+	hw_res_list_parsed_t hw_res_parsed;
+	hw_res_list_parsed_init(&hw_res_parsed);
+	if (hw_res_get_list_parsed(dev->parent_sess, &hw_res_parsed, 0) != EOK)
+		goto error_get_res_parsed;
+	
+	/* Register interrupt handler */
+	ahci_ranges[0].base = (size_t) hw_res_parsed.mem_ranges.ranges[0].address;
+	ahci_ranges[0].size = sizeof(ahci_dev_t);
+	ahci_cmds[0].addr =
+	    ((uint32_t *) (size_t) hw_res_parsed.mem_ranges.ranges[0].address) + 1;
+	ahci_cmds[1].addr =
+	    ((uint32_t *) (size_t) hw_res_parsed.mem_ranges.ranges[0].address) + 2;
+	ahci_cmds[2].addr = ahci_cmds[1].addr;
+	
+	irq_code_t ct;
+	ct.cmdcount = 3;
+	ct.cmds = ahci_cmds;
+	ct.rangecount = 1;
+	ct.ranges = ahci_ranges;
+	
+	int rc = register_interrupt_handler(dev, hw_res_parsed.irqs.irqs[0],
+	    ahci_interrupt, &ct);
+	
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed register_interrupt_handler function.");
+		goto error_register_interrupt_handler;
+	}
+	
+	if (ahci_pciintel_enable_interrupt(hw_res_parsed.irqs.irqs[0]) != EOK) {
+		ddf_msg(LVL_ERROR, "Failed enable interupt.");
+		goto error_enable_interrupt;
+	}
+	
+	/* Map AHCI register. */
+	physmem_map((void *) (size_t) (hw_res_parsed.mem_ranges.ranges[0].address),
+	    8, AS_AREA_READ | AS_AREA_WRITE, (void **) &ahci->memregs);
+	hw_res_list_parsed_clean(&hw_res_parsed);
+	
+	if (ahci->memregs == NULL)
+		goto error_map_registers;
+	
+	ahci->timer = fibril_timer_create();
+	
+	return ahci;
+	
+error_map_registers:
+error_enable_interrupt:
+error_register_interrupt_handler:
+	hw_res_list_parsed_clean(&hw_res_parsed);
+error_get_res_parsed:
+	return NULL;
+}
+
+static void ahci_ahci_init(ahci_dev_t *ahci)
+{
+	/* Enable interrupt and bus mastering */
+	ahci_pcireg_cmd_t cmd;
+	
+	pci_config_space_read_16(ahci->dev->parent_sess, AHCI_PCI_CMD, &cmd.u16);
+	cmd.id = 0;
+	cmd.bme = 1;
+	pci_config_space_write_16(ahci->dev->parent_sess, AHCI_PCI_CMD, cmd.u16);
+	
+	/* Set master latency timer */
+	pci_config_space_write_8(ahci->dev->parent_sess, AHCI_PCI_MLT, 32);
+	
+	/* Disable command completion coalescing feature. */
+	ahci_ghc_ccc_ctl_t ccc;
+	ccc.u32 = ahci->memregs->ghc.ccc_ctl;
+	ccc.en = 0;
+	ahci->memregs->ghc.ccc_ctl = ccc.u32;
+	
+	/* Enable AHCI and interrupt. */
+	ahci->memregs->ghc.ghc = AHCI_GHC_GHC_AE | AHCI_GHC_GHC_IE; 
+	
+	/* Enable timer. */
+	fibril_timer_set(ahci->timer, AHCI_TIMER_TICKS, ahci_timer, ahci);
+}
+
+static int ahci_dev_add(ddf_dev_t *dev)	
+{
+	dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+	    dev->handle, IPC_FLAG_BLOCKING);
+	if (dev->parent_sess == NULL)
+		return EINTR;
+	
+	ahci_dev_t *ahci = ahci_ahci_create(dev);
+	if (ahci == NULL)
+		return EINTR;
+	
+	dev->driver_data = ahci;
+	ahci_ahci_init(ahci);
+	ahci_sata_devices_create(ahci, dev);
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*-- Helpers and utilities ---------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
+
+static void ahci_get_model_name(uint16_t *src, char *dst)
+{
+	uint8_t model[40];
+	bzero(model, 40);
+	
+	for (unsigned int i = 0; i < 20; i++) {
+		uint16_t w = src[i];
+		model[2 * i] = w >> 8;
+		model[2 * i + 1] = w & 0x00ff;
+	}
+	
+	uint32_t len = 40;
+	while ((len > 0) && (model[len - 1] == 0x20))
+		len--;
+	
+	size_t pos = 0;
+	for (unsigned int i = 0; i < len; i++) {
+		uint8_t c = model[i];
+		if (c >= 0x80)
+			c = '?';
+		
+		chr_encode(c, dst, &pos, 40);
+	}
+	
+	dst[pos] = '\0';
+}
+
+static int ahci_pciintel_enable_interrupt(int irq)
+{
+	async_sess_t *irc_sess = NULL;
+	irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_IRC, 0, 0);
+	
+	if (!irc_sess)
+		return EINTR;
+	
+	async_exch_t *exch = async_exchange_begin(irc_sess);
+	const int rc = async_req_1_0(exch, IRC_ENABLE_INTERRUPT, irq);
+	async_exchange_end(exch);
+	
+	async_hangup(irc_sess);
+	return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+/*-- AHCI Main routine -------------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS AHCI device driver\n", NAME);
+	ddf_log_init(NAME, LVL_ERROR);
+	fibril_mutex_initialize(&sata_devices_count_lock);
+	return ddf_driver_main(&ahci_driver);
+}
Index: uspace/drv/block/ahci/ahci.h
===================================================================
--- uspace/drv/block/ahci/ahci.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/drv/block/ahci/ahci.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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.
+ */
+
+/** @file
+ * Header for AHCI driver.
+ */
+
+#ifndef __AHCI_H__
+#define __AHCI_H__
+
+#include <sys/types.h>
+#include <devman.h>
+#include <ddf/interrupt.h>
+#include <stdio.h>
+#include "ahci_hw.h"
+
+/** AHCI Device. */
+typedef struct {
+	/** Pointer to ddf device. */
+	ddf_dev_t *dev;
+	
+	/** Pointer to AHCI memory registers. */
+	ahci_memregs_t *memregs;
+	
+	/** AHCI device global timer. */
+	fibril_timer_t *timer;
+	
+	/** Pointers to sata devices. */
+	void *sata_devs[32];
+} ahci_dev_t;
+
+/** SATA Device. */
+typedef struct {
+	/** Pointer to AHCI device. */
+	ahci_dev_t *ahci;
+	
+	/** SATA port number(0-31). */
+	uint8_t port_num;
+	
+	/** Port interrupt states shadow registers. */
+	volatile ahci_port_is_t shadow_pxis;
+	
+	/** Device in invalid state (disconnected and so on). */
+	volatile bool invalid_device;
+	
+	/** Pointer to SATA port. */
+	volatile ahci_port_t *port;
+	/** Pointer to command header. */
+	volatile ahci_cmdhdr_t *cmd_header;
+	/** Pointer to command table. */
+	volatile uint32_t *cmd_table;
+	
+	/** Mutex for single operation on device. */
+	fibril_mutex_t lock;
+	
+	/** Mutex for event signaling condition variable. */
+	fibril_mutex_t event_lock;
+	/** Event signaling condition variable. */
+	fibril_condvar_t event_condvar;
+	
+	/** Block device service id. */
+	service_id_t service_id; 
+	
+	/** Number of device data blocks. */
+	uint64_t blocks;
+	/** Size of device data blocks. */
+	size_t block_size;
+	
+	/** Name of SATA device. */
+	char model[STR_BOUNDS(40) + 1];
+	
+	/** Device in invalid state (disconnected and so on). */
+	bool packet_device;
+	
+	/** Highest UDMA mode supported. */
+	uint8_t highest_udma_mode;
+} sata_dev_t;
+
+#endif
Index: uspace/drv/block/ahci/ahci.ma
===================================================================
--- uspace/drv/block/ahci/ahci.ma	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/drv/block/ahci/ahci.ma	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,3 @@
+10 pci/ven=8086&dev=2922
+10 pci/ven=8086&dev=2829
+10 pci/ven=1002&dev=4391
Index: uspace/drv/block/ahci/ahci_hw.h
===================================================================
--- uspace/drv/block/ahci/ahci_hw.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/drv/block/ahci/ahci_hw.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,1051 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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.
+ */
+
+/** @file
+ * Header for AHCI driver (AHCI 1.3 specification).
+ */
+
+#ifndef __AHCI_HW_H__
+#define __AHCI_HW_H__
+
+#include <sys/types.h>
+
+/*----------------------------------------------------------------------------*/
+/*-- AHCI PCI Registers ------------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
+
+/** AHCI PCI register Identifiers offset. */
+#define AHCI_PCI_ID     0x00
+/** AHCI PCI register Command offset. */
+#define AHCI_PCI_CMD    0x04
+/** AHCI PCI register Device Status offset. */
+#define AHCI_PCI_STS    0x06
+/** AHCI PCI register Revision ID offset. */
+#define AHCI_PCI_RID    0x08
+/** AHCI PCI register Class Codes offset. */
+#define AHCI_PCI_CC     0x09
+/** AHCI PCI register Cache Line Size offset. */
+#define AHCI_PCI_CLS    0x0C
+/** AHCI PCI register Master Latency Timer offset. */
+#define AHCI_PCI_MLT    0x0D
+/** AHCI PCI register Header Type offset. */
+#define AHCI_PCI_HTYPE  0x0E
+/** AHCI PCI register Built In Self Test (Optional) offset. */
+#define AHCI_PCI_BIST   0x0F
+/** AHCI PCI register Other Base Address Registres (Optional). */
+#define AHCI_PCI_BAR0   0x10
+/** AHCI PCI register Other Base Address Registres (Optional). */
+#define AHCI_PCI_BAR1   0x14
+/** AHCI PCI register Other Base Address Registres (Optional). */
+#define AHCI_PCI_BAR2   0x18
+/** AHCI PCI register Other Base Address Registres (Optional). */
+#define AHCI_PCI_BAR3   0x1C
+/** AHCI PCI register Other Base Address Registres (Optional). */
+#define AHCI_PCI_BAR4   0x20
+/** AHCI PCI register AHCI Base Address offset. */
+#define AHCI_PCI_ABAR   0x24
+/** AHCI PCI register Subsystem Identifiers offset. */
+#define AHCI_PCI_SS     0x2C
+/** AHCI PCI register Expansion ROM Base Address (Optional) offset. */
+#define AHCI_PCI_EROM   0x30
+/** AHCI PCI register Capabilities Pointer offset. */
+#define AHCI_PCI_CAP    0x34
+/** AHCI PCI register Interrupt Information offset. */
+#define AHCI_PCI_INTR   0x3C
+/** AHCI PCI register Min Grant (Optional) offset. */
+#define AHCI_PCI_MGNT   0x3E
+/** AHCI PCI register Max Latency (Optional) offset. */
+#define AHCI_PCI_MLAT   0x3F
+
+/** AHCI PCI register Identifiers. */
+typedef struct {
+	/** Indicates the company vendor assigned by the PCI SIG. */
+	uint16_t vendorid;
+	/** Indicates what device number assigned by the vendor */
+	uint16_t deviceid;
+} ahci_pcireg_id_t;
+
+/** AHCI PCI register Command. */
+typedef union {
+	struct {
+		/** I/O Space Enable. */
+		unsigned int iose : 1;
+		/** Memory Space Enable. */
+		unsigned int mse : 1;
+		/** Bus Master Enable. */
+		unsigned int bme : 1;
+		/** Special Cycle Enable. */
+		unsigned int sce : 1;
+		/** Memory Write and Invalidate Enable. */
+		unsigned int mwie : 1;
+		/** VGA Palette Snooping Enable. */
+		unsigned int vga : 1;
+		/** Parity Error Response Enable. */
+		unsigned int pee : 1;
+		/** Wait Cycle Enable. */
+		unsigned int wcc : 1;
+		/** SERR# Enable. */
+		unsigned int see : 1;
+		/** Fast Back-to-Back Enable. */
+		unsigned int fbe : 1;
+		/** Interrupt Disable - disables the HBA from generating interrupts.
+		 * This bit does not have any effect on MSI operation.
+		 */
+		unsigned int id : 1;
+		/** Reserved. */
+		unsigned int reserved : 5;
+	};
+	uint16_t u16;
+} ahci_pcireg_cmd_t;
+
+/** AHCI PCI register Command - Interrupt Disable bit. */
+#define AHCI_PCIREG_CMD_ID  0x0400
+
+/** AHCI PCI register Command - Bus Master Enable bit. */
+#define AHCI_PCIREG_CMD_BME  0x0004
+
+/** AHCI PCI register Device status. */
+typedef union {
+	struct {
+		/** Reserved. */
+		unsigned int reserved1 : 3;
+		/** Indicate the interrupt status of the device (1 = asserted). */
+		unsigned int is : 1;
+		/** Indicates presence of capatibility list. */
+		unsigned int cl : 1;
+		/** 66 Mhz capable. */
+		unsigned int c66 : 1;
+		/** Reserved. */
+		unsigned int reserved2 : 1;
+		/** Fast back to back capable. */
+		unsigned int fbc : 1;
+		/** Master data parity error detected. */
+		unsigned int dpd : 1;
+		/** Device select timing. */
+		unsigned int devt : 2;
+		/** Signaled target abort. */
+		unsigned int sta : 1;
+		/** Received target abort. */
+		unsigned int rta : 1;
+		/** Received master abort. */
+		unsigned int rma : 1;
+		/** Signaled system error. */
+		unsigned int sse : 1;
+		/** Detected parity error. */
+		unsigned int dpe : 1;
+	};
+	uint16_t u16;
+} ahci_pcireg_sts_t;
+
+/** AHCI PCI register Revision ID. */
+typedef struct {
+	/** Indicates stepping of the HBA hardware. */
+	uint8_t u8;
+} ahci_pcireg_rid_t;
+
+/** AHCI PCI register Class Codes. */
+typedef struct {
+	/** Programing interface, when set to 01h and the scc is set to 06h,
+	 * indicates that this an AHCI HBA major revision 1.
+	 */
+	uint8_t pi;
+	/** When set to 06h, indicates that is a SATA device. */
+	uint8_t scc;
+	/** Value 01 indicates that is a mass storage device. */
+	uint8_t bcc;
+} ahci_pcireg_cc_t_t;
+
+/** AHCI PCI register Cache Line Size. */
+typedef struct {
+	/** Cache line size for use with the memory write and invalidate command. */
+	uint8_t u8;
+} ahci_pcireg_cls_t;
+
+/** AHCI PCI register Master Latency Timer. */
+typedef struct {
+	/** Master latency timer,indicates the number of clocks the HBA is allowed
+	 * to acts as master on PCI.
+	 */
+	uint8_t u8;
+} ahci_pcireg_mlt_t;
+
+/** AHCI PCI register Header Type. */
+typedef union {
+	struct {
+		 /** Header layout. */
+		unsigned int hl : 7;
+		/** Multi function device. */
+		unsigned int mfd : 1;
+	};
+	uint8_t u8;
+} ahci_pciregs_htype_t;
+
+/** AHCI PCI register Built in self test. */
+typedef union {
+	struct {
+	/** Indicates the completion status of BIST
+	 * non-zero value indicates a failure.
+	 */
+	unsigned int cc : 4;
+	/** Reserved. */
+	unsigned int reserved : 2;
+	/** Software sets this bit to 1 to invoke BIST,
+	 * the HBA clears this bit to 0 when BIST is complete.
+	 */
+	unsigned int sb : 1;
+	/** BIST capable. */
+	unsigned int bc : 1;
+	};
+	uint8_t u8;
+} ahci_pciregs_bist_t;
+
+/** AHCI PCI register AHCI Base Address <BAR 5>. */
+typedef union {
+	struct {
+		/** Indicates a request for register memory space. */
+		unsigned int rte : 1;
+		/** Indicates the this range can be mapped anywhere in 32-bit address
+		 * space.
+		 */
+		unsigned int tp : 2;
+		/** Indicate that this range is not prefetchable. */
+		unsigned int pf : 1;
+		/** Reserved. */
+		unsigned int reserved : 9;
+		/** Base address of registry memory space. */
+		unsigned int ba : 19;
+	};
+	uint32_t u32;
+} ahci_pciregs_abar_t;
+
+/** AHCI PCI register Subsystem Identifiers. */
+typedef struct
+{
+	/** Sub system vendor identifier. */
+	uint8_t ssvid;
+	/** Sub system identifier. */
+	uint8_t ssid;
+} ahci_pcireg_ss_t;
+
+/** AHCI PCI registers Expansion ROM Base Address. */
+typedef struct
+{
+	/** Indicates the base address of the HBA expansion ROM. */
+	uint32_t u32;
+} ahci_pcireg_erom_t;
+
+/** AHCI PCI register Capabilities Pointer. */
+typedef struct
+{
+	/** Indicates the first capability pointer offset. */
+	uint8_t u8;
+} ahci_pcireg_cap_t;
+
+/** AHCI PCI register Interrupt Information. */
+typedef struct
+{
+	/* Software written value to indicate which interrupt vector
+	 * the interrupt is connected to.
+	 */
+	uint8_t iline;
+	/** This indicates the interrupt pin the HBA uses. */
+	uint8_t ipin;
+} ahci_pcireg_intr;
+
+/** AHCI PCI register Min Grant (Optional). */
+typedef struct
+{
+	/** Indicates the minimum grant time (in ? microseconds)
+	 * that the device wishes grant asserted.
+	 */
+	uint8_t u8;
+} ahci_pcireg_mgnt_t;
+
+/** AHCI PCI register Max Latency (Optional). */
+typedef struct
+{
+	/** Indicates the maximum latency that the device can withstand. */
+	uint8_t u8;
+} ahci_pcireg_mlat_t;
+
+/*----------------------------------------------------------------------------*/
+/*-- AHCI Memory Registers ---------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
+
+/** AHCI Memory register Generic Host Control - HBA Capabilities. */
+typedef union {
+	struct {
+		/** Number of Ports. */
+		unsigned int np : 5;
+		/** Supports External SATA. */
+		unsigned int sxs : 1;
+		/** Enclosure Management Supported. */
+		unsigned int ems : 1;
+		/** Command Completion Coalescing Supported. */
+		unsigned int cccs : 1;
+		/** Number of Command Slots. */
+		unsigned int ncs : 5;
+		/** Partial State Capable. */
+		unsigned int psc : 1;
+		/** Slumber State Capable. */
+		unsigned int ssc : 1;
+		/** PIO Multiple DRQ Block. */
+		unsigned int pmd : 1;
+		/** FIS-based Switching Supported. */
+		unsigned int fbss : 1;
+		/** Supports Port Multiplier. */
+		unsigned int spm : 1;
+		/** Supports AHCI mode only. */
+		unsigned int sam : 1;
+		/** Reserved. */
+		unsigned int reserved : 1;
+		/** Interface Speed Support. */
+		unsigned int iss : 4;
+		/** Supports Command List Override. */
+		unsigned int sclo : 1;
+		/** Supports Activity LED. */
+		unsigned int sal : 1;
+		/** Supports Aggressive Link Power Management. */
+		unsigned int salp : 1;
+		/** Supports Staggered Spin-up. */
+		unsigned int sss : 1;
+		/** Supports Mechanical Presence Switch. */
+		unsigned int smps : 1;
+		/** Supports SNotification Register. */
+		unsigned int ssntf : 1;
+		/** Supports Native Command Queuing. */
+		unsigned int sncq : 1;
+		/** Supports 64-bit Addressing. */
+		unsigned int s64a : 1;
+	};
+	uint32_t u32;
+} ahci_ghc_cap_t;
+
+/** AHCI Memory register Generic Host Control Global Host Control. */
+typedef union {
+	struct {
+		/** HBA Reset. */
+		unsigned int hr : 1;
+		/** Interrupt Enable. */
+		unsigned int ie : 1;
+		/** MSI Revert to Single Message. */
+		unsigned int mrsm : 1;
+		/** Reserved. */
+		unsigned int reserved : 28;
+		/** AHCI Enable. */
+		unsigned int ae : 1;
+	};
+	uint32_t u32;
+} ahci_ghc_ghc_t;
+
+/** AHCI Enable mask bit. */
+#define AHCI_GHC_GHC_AE  0x80000000
+
+/** AHCI Interrupt Enable mask bit. */
+#define AHCI_GHC_GHC_IE  0x00000002
+
+/** AHCI Memory register Interrupt pending register. */
+typedef struct {
+	/** Interrupt pending status, if set, indicates that
+	 * the corresponding port has an interrupt pending.
+	 */
+	uint32_t u32;
+} ahci_ghc_is_t;
+
+/** AHCI Memory register Ports implemented. */
+typedef struct {
+	/** If a bit is set to 1, the corresponding port
+	 * is available for software use.
+	 */
+	uint32_t u32;
+} ahci_ghc_pi_t;
+
+/** AHCI Memory register AHCI version. */
+typedef struct {
+	/** Indicates the minor version */
+	uint16_t mnr;
+	/** Indicates the major version */
+	uint16_t mjr;
+} ahci_ghc_vs_t;
+
+/** AHCI Memory register Command completion coalesce control. */
+typedef union {
+	struct {
+		/** Enable CCC features. */
+		unsigned int en : 1;
+		/** Reserved. */
+		unsigned int reserved : 2;
+		/** Interrupt number for CCC. */
+		unsigned int intr : 5;
+		/** Number of command completions that are necessary to cause
+		 * a CCC interrupt.
+		 */
+		uint8_t cc;
+		/** Timeout value in  ms. */
+		uint16_t tv;
+	};
+	uint32_t u32;
+} ahci_ghc_ccc_ctl_t;
+
+/** AHCI Memory register Command completion coalescing ports. */
+typedef struct
+{
+	/** If a bit is set to 1, the corresponding port is
+	 * part of the command completion coalescing feature.
+	 */
+	uint32_t u32;
+} ahci_ghc_ccc_ports_t;
+
+/** AHCI Memory register Enclosure management location. */
+typedef struct
+{
+	/** Size of the transmit message buffer area in dwords. */
+	uint16_t sz;
+	/* Offset of the transmit message buffer area in dwords
+	 * from the beginning of ABAR
+	 */
+	uint16_t ofst;
+} ahci_ghc_em_loc;
+
+/** AHCI Memory register Enclosure management control. */
+typedef union {
+	struct {
+		/** Message received. */
+		unsigned int mr : 1;
+		/** Reserved. */
+		unsigned int reserved : 7;
+		/** Transmit message. */
+		unsigned int tm : 1;
+		/** Reset. */
+		unsigned int rst : 1;
+		/** Reserved. */
+		unsigned int reserved2 : 6;
+		/** LED message types. */
+		unsigned int led : 1;
+		/** Support SAFT-TE message type. */
+		unsigned int safte : 1;
+		/** Support SES-2 message type. */
+		unsigned int ses2 : 1;
+		/** Support SGPIO register. */
+		unsigned int sgpio : 1;
+		/** Reserved. */
+		unsigned int reserved3 : 4;
+		/** Single message buffer. */
+		unsigned int smb : 1;
+		/**  Support transmitting only. */
+		unsigned int xmt : 1;
+		/** Activity LED hardware driven. */
+		unsigned int alhd : 1;
+		/** port multiplier support. */
+		unsigned int pm : 1;
+		/** Reserved. */
+		unsigned int reserved4 : 4;
+	};
+	uint32_t u32;
+} ahci_ghc_em_ctl_t;
+
+/** AHCI Memory register HBA capatibilities extended. */
+typedef union {
+	struct {
+		/** HBA support BIOS/OS handoff mechanism,
+		 * implemented BOHC register.
+		 */
+		unsigned int boh : 1;
+		/** Support for NVMHCI register. */
+		unsigned int nvmp : 1;
+		/** Automatic partial to slumber transition support. */
+		unsigned int apst : 1;
+		/** Reserved. */
+		unsigned int reserved : 29;
+	};
+	uint32_t u32;
+} ahci_ghc_cap2_t;
+
+/** AHCI Memory register BIOS/OS Handoff control and status. */
+typedef union {
+	struct {
+		/** BIOS Owned semaphore. */
+		unsigned int bos : 1;
+		/** OS Owned semaphore. */
+		unsigned int oos : 1;
+		/** SMI on OS ownership change enable. */
+		unsigned int sooe : 1;
+		/** OS ownership change. */
+		unsigned int ooc : 1;
+		/** BIOS Busy. */
+		unsigned int bb : 1;
+		/** Reserved. */
+		unsigned int reserved : 27;
+	};
+	uint32_t u32;
+} ahci_ghc_bohc_t;
+
+/** AHCI Memory register Generic Host Control. */
+typedef struct
+{
+	/** Host Capabilities. */
+	uint32_t cap;
+	/** Global Host Control. */
+	uint32_t ghc;
+	/** Interrupt Status. */
+	uint32_t is;
+	/** Ports Implemented. */
+	uint32_t pi;
+	/** Version. */
+	uint32_t vs;
+	/** Command Completion Coalescing Control. */
+	uint32_t ccc_ctl;
+	/** Command Completion Coalsecing Ports. */
+	uint32_t ccc_ports;
+	/** Enclosure Management Location. */
+	uint32_t em_loc;
+	/** Enclosure Management Control. */
+	uint32_t em_ctl;
+	/** Host Capabilities Extended. */
+	uint32_t cap2;
+	/** BIOS/OS Handoff Control and Status. */
+	uint32_t bohc;
+} ahci_ghc_t;
+
+/** AHCI Memory register Port x Command List Base Address. */
+typedef union {
+	struct {
+		/** Reserved. */
+		unsigned int reserved : 10;
+		/** Command List Base Address (CLB) - Indicates the 32-bit base physical
+		 * address for the command list for this port. This base is used when
+		 * fetching commands to execute. The structure pointed to by this
+		 * address range is 1K-bytes in length. This address must be 1K-byte
+		 * aligned as indicated by bits 09:00 being read only.
+		 */
+		unsigned int clb : 22;
+	};
+	uint32_t u32;
+} ahci_port_clb_t;
+
+/** AHCI Memory register Port x Command List Base Address Upper 32-Bits. */
+typedef struct {
+	/** Command List Base Address Upper (CLBU): Indicates the upper 32-bits
+	 * for the command list base physical address for this port. This base
+	 * is used when fetching commands to execute. This register shall
+	 * be read only for HBAs that do not support 64-bit addressing.
+	 */
+	uint32_t u32;
+} ahci_port_clbu_t;
+
+/** AHCI Memory register Port x FIS Base Address. */
+typedef union {
+	struct {
+		/** Reserved. */
+		unsigned int reserved : 8;
+		/** FIS Base Address (FB) - Indicates the 32-bit base physical address
+		 * for received FISes. The structure pointed to by this address range
+		 * is 256 bytes in length. This address must be 256-byte aligned as
+		 * indicated by bits 07:00 being read only. When FIS-based switching
+		 * is in use, this structure is 4KB in length and the address shall be
+		 * 4KB aligned.
+		 */
+		unsigned int fb : 24;
+	};
+	uint32_t u32;
+} ahci_port_fb_t;
+
+/** AHCI Memory register Port x FIS Base Address Upper 32-Bits. */
+typedef struct {
+	/** FIS Base Address Upper (FBU) - Indicates the upper 32-bits
+	 * for the received FIS base physical address for this port. This register
+	 * shall be read only for HBAs that do not support 64-bit addressing.
+	 */
+	uint32_t u32;
+} ahci_port_fbu_t;
+
+/** AHCI Memory register Port x Interrupt Status. */
+typedef union {
+	struct {
+		/** Device to Host Register FIS Interrupt. */
+		unsigned int dhrs : 1;
+		/** PIO Setup FIS Interrupt. */
+		unsigned int pss : 1;
+		/** DMA Setup FIS Interrupt. */
+		unsigned int dss : 1;
+		/** Set Device Bits Interrupt. */
+		unsigned int sdbs : 1;
+		/** Unknown FIS Interrupt. */
+		unsigned int ufs : 1;
+		/** Descriptor Processed. */
+		unsigned int dps : 1;
+		/** Port Connect Change Status. */
+		unsigned int pcs : 1;
+		/** Device Mechanical Presence Status. */
+		unsigned int dmps : 1;
+		/** Reserved. */
+		unsigned int reserved1 : 14;
+		/** PhyRdy Change Status. */
+		unsigned int prcs : 1;
+		/** Incorrect Port Multiplier Status. */
+		unsigned int ipms : 1;
+		/** Overflow Status. */
+		unsigned int ofs : 1;
+		/** Reserved. */
+		unsigned int reserved2 : 1;
+		/** Interface Non-fatal Error Status. */
+		unsigned int infs : 1;
+		/** Interface Fatal Error Status. */
+		unsigned int ifs : 1;
+		/** Host Bus Data Error Status. */
+		unsigned int hbds : 1;
+		/** Host Bus Fatal Error Status. */
+		unsigned int hbfs : 1;
+		/** Task File Error Status. */
+		unsigned int tfes : 1;
+		/** Cold Port Detect Status. */
+		unsigned int cpds : 1;
+	};
+	uint32_t u32;
+} ahci_port_is_t;
+
+#define AHCI_PORT_IS_DHRS  (1 << 0)
+#define AHCI_PORT_IS_PSS   (1 << 1)
+#define AHCI_PORT_IS_DSS   (1 << 2)
+#define AHCI_PORT_IS_SDBS  (1 << 3)
+#define AHCI_PORT_IS_UFS   (1 << 4)
+#define AHCI_PORT_IS_DPS   (1 << 5)
+#define AHCI_PORT_IS_PCS   (1 << 6)
+#define AHCI_PORT_IS_DMPS  (1 << 7)
+
+#define AHCI_PORT_IS_PRCS  (1 << 22)
+#define AHCI_PORT_IS_IPMS  (1 << 23)
+#define AHCI_PORT_IS_OFS   (1 << 24)
+#define AHCI_PORT_IS_INFS  (1 << 26)
+#define AHCI_PORT_IS_IFS   (1 << 27)
+#define AHCI_PORT_IS_HDBS  (1 << 28)
+#define AHCI_PORT_IS_HBFS  (1 << 29)
+#define AHCI_PORT_IS_TFES  (1 << 30)
+#define AHCI_PORT_IS_CPDS  (1 << 31)
+
+#define AHCI_PORT_END_OF_OPERATION \
+	(AHCI_PORT_IS_DHRS | \
+	AHCI_PORT_IS_SDBS )
+
+#define AHCI_PORT_IS_ERROR \
+	(AHCI_PORT_IS_UFS | \
+	AHCI_PORT_IS_PCS | \
+	AHCI_PORT_IS_DMPS | \
+	AHCI_PORT_IS_PRCS | \
+	AHCI_PORT_IS_IPMS | \
+	AHCI_PORT_IS_OFS | \
+	AHCI_PORT_IS_INFS | \
+	AHCI_PORT_IS_IFS | \
+	AHCI_PORT_IS_HDBS | \
+	AHCI_PORT_IS_HBFS | \
+	AHCI_PORT_IS_TFES | \
+	AHCI_PORT_IS_CPDS)
+
+#define AHCI_PORT_IS_PERMANENT_ERROR \
+	(AHCI_PORT_IS_PCS | \
+	AHCI_PORT_IS_DMPS | \
+	AHCI_PORT_IS_PRCS | \
+	AHCI_PORT_IS_IPMS | \
+	AHCI_PORT_IS_CPDS )
+
+/** Evaluate end of operation status from port interrupt status.
+ *
+ * @param port_is Value of port interrupt status.
+ *
+ * @return Indicate end of operation status.
+ *
+ */
+static inline int ahci_port_is_end_of_operation(ahci_port_is_t port_is)
+{
+	return port_is.u32 & AHCI_PORT_END_OF_OPERATION;
+}
+
+/** Evaluate error status from port interrupt status.
+ *
+ * @param port_is Value of port interrupt status.
+ *
+ * @return Indicate error status.
+ *
+ */
+static inline int ahci_port_is_error(ahci_port_is_t port_is)
+{
+	return port_is.u32 & AHCI_PORT_IS_ERROR;
+}
+
+/** Evaluate permanent error status from port interrupt status.
+ *
+ * @param port_is Value of port interrupt status.
+ *
+ * @return Indicate permanent error status.
+ *
+ */
+static inline int ahci_port_is_permanent_error(ahci_port_is_t port_is)
+{
+	return port_is.u32 & AHCI_PORT_IS_PERMANENT_ERROR;
+}
+
+/** Evaluate task file error status from port interrupt status.
+ *
+ * @param port_is Value of port interrupt status.
+ *
+ * @return Indicate error status.
+ *
+ */
+static inline int ahci_port_is_tfes(ahci_port_is_t port_is)
+{
+	return port_is.u32 & AHCI_PORT_IS_TFES;
+}
+
+/** AHCI Memory register Port x Interrupt Enable. */
+typedef union {
+	struct {
+		/** Device to Host Register FIS Interrupt Enable. */
+		unsigned int dhre : 1;
+		/** PIO Setup FIS Interrupt Enable. */
+		unsigned int pse : 1;
+		/** DMA Setup FIS Interrupt Enable. */
+		unsigned int dse : 1;
+		/** Set Device Bits Interrupt Eenable. */
+		unsigned int sdbe : 1;
+		/** Unknown FIS Interrupt Enable. */
+		unsigned int ufe : 1;
+		/** Descriptor Processed Interrupt Enable. */
+		unsigned int dpe : 1;
+		/** Port Change Interrupt Enable. */
+		unsigned int pce : 1;
+		/** Device Mechanical Presence Enable. */
+		unsigned int dmpe : 1;
+		/** Reserved. */
+		unsigned int reserved1 : 14;
+		/** PhyRdy Change Interrupt Enable. */
+		unsigned int prce : 1;
+		/** Incorrect Port Multiplier Enable. */
+		unsigned int ipme : 1;
+		/** Overflow Status Enable. */
+		unsigned int ofe : 1;
+		/** Reserved. */
+		unsigned int reserved2 : 1;
+		/** Interface Non-fatal Error Enable. */
+		unsigned int infe : 1;
+		/** Interface Fatal Error Enable. */
+		unsigned int ife : 1;
+		/** Host Bus Data Error Enable. */
+		unsigned int hbde : 1;
+		/** Host Bus Fatal Error Enable. */
+		unsigned int hbfe : 1;
+		/** Task File Error Enable. */
+		unsigned int tfee : 1;
+		/** Cold Port Detect Enable. */
+		unsigned int cpde : 1;
+	};
+	uint32_t u32;
+} ahci_port_ie_t;
+
+/** AHCI Memory register Port x Command and Status. */
+typedef union {
+	struct {
+		/** Start - when set, the HBA may process the command list. */
+		unsigned int st : 1;
+		/** Spin-Up Device. */
+		unsigned int sud : 1;
+		/** Power On Device. */
+		unsigned int pod : 1;
+		/** Command List Override. */
+		unsigned int clo : 1;
+		/** FIS Receive Enable. */
+		unsigned int fre : 1;
+		/** Reserved. */
+		unsigned int reserved : 3;
+		/** Current Command Slot. */
+		unsigned int ccs : 5;
+		/** Mechanical Presence Switch State. */
+		unsigned int mpss : 1;
+		/** FIS Receive Running. */
+		unsigned int fr : 1;
+		/** Command List Running. */
+		unsigned int cr : 1;
+		/** Cold Presence State. */
+		unsigned int cps : 1;
+		/** Port Multiplier Attached. */
+		unsigned int pma : 1;
+		/** Hot Plug Capable Port. */
+		unsigned int hpcp : 1;
+		/** Mechanical Presence Switch Attached to Port. */
+		unsigned int mpsp : 1;
+		/** Cold Presence Detection. */
+		unsigned int cpd : 1;
+		/** External SATA Port. */
+		unsigned int esp : 1;
+		/** FIS-based Switching Capable Port. */
+		unsigned int fbscp : 1;
+		/** Automatic Partial to Slumber Transitions Enabled. */
+		unsigned int apste : 1;
+		/** Device is ATAPI. */
+		unsigned int atapi : 1;
+		/** Drive LED on ATAPI Enable. */
+		unsigned int dlae : 1;
+		/** Aggressive Link Power Management Enable. */
+		unsigned int alpe : 1;
+		/** Aggressive Slumber / Partial. */
+		unsigned int asp : 1;
+		/** Interface Communication Control.
+		 * Values:
+		 * 7h - fh Reserved,
+		 * 6h Slumber - This shall cause the HBA to request a transition of the
+		 *    interface to the Slumber state,
+		 * 3h - 5h Reserved,
+		 * 2h Partial - This shall cause the HBA to request a transition of the
+		 *    interface to the Partial state,
+		 * 1h Active,
+		 * 0h No-Op / Idle.
+		 */
+		unsigned int icc : 4;
+	};
+	uint32_t u32;
+} ahci_port_cmd_t;
+
+/** AHCI Memory register Port x Task File Data. */
+typedef union {
+	struct {
+		/** Status (STS): Contains the latest copy of the task file
+		 * status register.
+		 */
+		uint8_t sts;
+		/** Error (ERR) - Contains the latest copy of the task file
+		 * error register.
+		 */
+		uint8_t err;
+		/** Reserved. */
+		uint16_t reserved;
+	};
+	uint32_t u32;
+} ahci_port_tfd_t;
+
+/** AHCI Memory register Port x Signature. */
+typedef union {
+	struct {
+		/** Sector Count Register */
+		uint8_t sector_count;
+		/** LBA Low Register */
+		uint8_t lba_lr;
+		/** LBA Mid Register */
+		uint8_t lba_mr;
+		/**  LBA High Register */
+		uint8_t lba_hr;
+	};
+	uint32_t u32;
+} ahci_port_sig_t;
+
+/** AHCI Memory register Port x Serial ATA Status (SCR0: SStatus). */
+typedef union {
+	struct {
+		/** Device Detection */
+		unsigned int det : 4;
+		/** Current Interface Speed */
+		unsigned int spd : 4;
+		/** Interface Power Management */
+		unsigned int ipm : 4;
+		/** Reserved. */
+		unsigned int reserved : 20;
+	};
+	uint32_t u32;
+} ahci_port_ssts_t;
+
+/** AHCI Memory register Port x Serial ATA Control (SCR2: SControl). */
+typedef union {
+	struct {
+		/** Device Detection Initialization */
+		unsigned int det : 4;
+		/** Speed Allowed */
+		unsigned int spd : 4;
+		/** Interface Power Management Transitions Allowed */
+		unsigned int ipm : 4;
+		/** Reserved. */
+		unsigned int reserved : 20;
+	};
+	uint32_t u32;
+} ahci_port_sctl_t;
+
+/** AHCI Memory register Port x Port x Serial ATA Error (SCR1: SError). */
+typedef struct {
+	/** Error (ERR) - The ERR field contains error information for use
+	 * by host software in determining the appropriate response to the
+	 * error condition.
+	 */
+	uint16_t err;
+	/** Diagnostics (DIAG) - Contains diagnostic error information for use
+	 * by diagnostic software in validating correct operation or isolating
+	 * failure modes.
+	 */
+	uint16_t diag;
+} ahci_port_serr_t;
+
+/** AHCI Memory register Port x Serial ATA Active (SCR3: SActive). */
+typedef struct {
+	/** Device Status - Each bit corresponds to the TAG and
+	 * command slot of a native queued command, where bit 0 corresponds
+	 * to TAG 0 and command slot 0.
+	 */
+	uint32_t u32;
+} ahci_port_sact_t;
+
+/** AHCI Memory register Port x Command Issue. */
+typedef struct {
+	/** Commands Issued - Each bit corresponds to a command slot,
+	 *  where bit 0 corresponds to command slot 0.
+	 */
+	uint32_t u32;
+} ahci_port_ci_t;
+
+/** AHCI Memory register Port x Serial ATA Notification
+ * (SCR4: SNotification).
+ */
+typedef struct {
+	/** PM Notify (PMN): This field indicates whether a particular device with
+	 * the corresponding PM Port number issued a Set Device Bits FIS
+	 * to the host with the Notification bit set.
+	 */
+	uint16_t pmn;
+	/** Reserved. */
+	uint16_t reserved;
+} ahci_port_sntf_t;
+
+/** AHCI Memory register Port x FIS-based Switching Control.
+ * This register is used to control and obtain status
+ * for Port Multiplier FIS-based switching.
+ */
+typedef union {
+	struct {
+		/** Enable */
+		unsigned int en : 1;
+		/** Device Error Clear */
+		unsigned int dec : 1;
+		/** Single Device Error */
+		unsigned int sde : 1;
+		/** Reserved. */
+		unsigned int reserved1 : 5;
+		/** Device To Issue */
+		unsigned int dev : 1;
+		/** Active Device Optimization */
+		unsigned int ado : 1;
+		/** Device With Error */
+		unsigned int dwe : 1;
+		/** Reserved. */
+		unsigned int reserved2 : 1;
+	};
+	uint32_t u32;
+} ahci_port_fbs_t;
+
+/** AHCI Memory register Port. */
+typedef volatile struct
+{
+	/** Port x Command List Base Address. */
+	uint32_t pxclb;
+	/** Port x Command List Base Address Upper 32-Bits. */
+	uint32_t pxclbu;
+	/** Port x FIS Base Address. */
+	uint32_t pxfb;
+	/** Port x FIS Base Address Upper 32-Bits. */
+	uint32_t pxfbu;
+	/** Port x Interrupt Status. */
+	uint32_t pxis;
+	/** Port x Interrupt Enable. */
+	uint32_t pxie;
+	/** Port x Command and Status. */
+	uint32_t pxcmd;
+	/** Reserved. */
+	uint32_t reserved1;
+	/** Port x Task File Data. */
+	uint32_t pxtfd;
+	/**  Port x Signature. */
+	uint32_t pxsig;
+	/** Port x Serial ATA Status (SCR0: SStatus). */
+	uint32_t pxssts;
+	/** Port x Serial ATA Control (SCR2: SControl). */
+	uint32_t pxsctl;
+	/** Port x Serial ATA Error (SCR1: SError). */
+	uint32_t pxserr;
+	/** Port x Serial ATA Active (SCR3: SActive). */
+	uint32_t pxsact;
+	/** Port x Command Issue. */
+	uint32_t pxci;
+	/** Port x Serial ATA Notification (SCR4: SNotification). */
+	uint32_t pxsntf;
+	/** Port x FIS-based Switching Control. */
+	uint32_t pxfbs;
+	/** Reserved. */
+	uint32_t reserved2[11];
+	/** Port x Vendor Specific. */
+	uint32_t pxvs[4];
+} ahci_port_t;
+
+/** AHCI Memory Registers. */
+typedef volatile struct {
+	/** Generic Host Control. */
+	ahci_ghc_t ghc;
+	/** Reserved. */
+	uint8_t reserved[52];
+	/** Reserved for NVMHCI. */
+	uint8_t reservedfornvmhci[64];
+	/** Vendor Specific registers. */
+	uint8_t vendorspecificsregs[96];
+	/** Ports. */
+	ahci_port_t ports[32];
+} ahci_memregs_t;
+
+/** AHCI Command header entry. */
+typedef volatile struct {
+	/** Flags. */
+	uint16_t flags;
+	/** Physical Region Descriptor Table Length. */
+	uint16_t prdtl;
+	/** Physical Region Descriptor Byte Count. */
+	uint32_t bytesprocessed;
+	 /** Command Table Descriptor Base Address. */
+	uint32_t cmdtable;
+	/** Command Table Descriptor Base Address Upper 32-bits. */
+	uint32_t cmdtableu;
+} ahci_cmdhdr_t;
+
+/** AHCI Command Physical Region Descriptor entry. */
+typedef volatile struct {
+	/** Word aligned 32-bit data base address. */
+	uint32_t data_address_low;
+	/** Upper data base address, valid only for 64-bit HBA addressing. */
+	uint32_t data_address_upper;
+	/** Reserved. */
+	uint32_t reserved1;
+	/** Data byte count */
+	unsigned int dbc : 22;
+	/** Reserved */
+	unsigned int reserved2 : 9;
+	/** Interrupt on completion */
+	unsigned int ioc : 1;
+} ahci_cmd_prdt_t;
+
+#endif
Index: uspace/drv/block/ahci/ahci_sata.h
===================================================================
--- uspace/drv/block/ahci/ahci_sata.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/drv/block/ahci/ahci_sata.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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.
+ */
+
+/** @file
+ * Header for AHCI driver (SATA/ATA and related things).
+ */
+
+#ifndef __AHCI_SATA_H__
+#define __AHCI_SATA_H__
+
+#include <sys/types.h>
+
+/** Standard Command frame. */
+typedef struct {
+	/** FIS type - always 0x27. */
+	unsigned int fis_type : 8;
+	/** Indicate that FIS is a Command - always 0x80. */
+	unsigned int c : 8;
+	/** Command - Identity device - 0xec, Set fetures - 0xef. */
+	unsigned int command : 8;
+	/** Features - subcommand for set features - set tranfer mode - 0x03. */
+	unsigned int features : 8;
+	/** 0:23 bits of LBA. */
+	unsigned int lba_lower : 24;
+	/** Device. */
+	unsigned int device : 8;
+	/** 24:47 bits of LBA. */
+	unsigned int lba_upper : 24;
+	/** Features - subcommand for set features - set tranfer mode - 0x03. */
+	unsigned int features_upper : 8;
+	/** Sector count - transfer mode for set transfer mode operation. */
+	unsigned int count : 16;
+	/** Reserved. */
+	unsigned int reserved1 : 8;
+	/** Control. */
+	unsigned int control : 8;
+	/** Reserved. */
+	unsigned int reserved2 : 32;
+} std_command_frame_t;
+
+/** Command frame for NCQ data operation. */
+typedef struct {
+	/** FIS type - always 0x27. */
+	uint8_t fis_type;
+	/** Indicate that FIS is a Command - always 0x80. */
+	uint8_t c;
+	/** Command - FPDMA Read - 0x60, FPDMA Write - 0x61. */
+	uint8_t command;
+	/** bits 7:0 of sector count. */
+	uint8_t sector_count_low;
+	/** bits 7:0 of lba. */
+	uint8_t lba0;
+	/** bits 15:8 of lba. */
+	uint8_t lba1;
+	/** bits 23:16 of lba. */
+	uint8_t lba2;
+	uint8_t fua;
+	/** bits 31:24 of lba. */
+	uint8_t lba3;
+	/** bits 39:32 of lba. */
+	uint8_t lba4;
+	/** bits 47:40 of lba. */
+	uint8_t lba5;
+	/** bits 15:8 of sector count. */
+	uint8_t sector_count_high;
+	/** Tag number of NCQ operation. */
+	uint8_t tag;
+	/** Reserved. */
+	uint8_t reserved1;
+	/** Reserved. */
+	uint8_t reserved2;
+	/** Control. */
+	uint8_t control;
+	/** Reserved. */
+	uint8_t reserved3;
+	/** Reserved. */
+	uint8_t reserved4;
+	/** Reserved. */
+	uint8_t reserved5;
+	/** Reserved. */
+	uint8_t reserved6;
+} ncq_command_frame_t;
+
+/** Data returned from identify device and identify packet device command. */
+typedef struct {
+	uint16_t gen_conf;
+	uint16_t cylinders;
+	uint16_t reserved2;
+	uint16_t heads;
+	uint16_t _vs4;
+	uint16_t _vs5;
+	uint16_t sectors;
+	uint16_t _vs7;
+	uint16_t _vs8;
+	uint16_t _vs9;
+	
+	uint16_t serial_number[10];
+	uint16_t _vs20;
+	uint16_t _vs21;
+	uint16_t vs_bytes;
+	uint16_t firmware_rev[4];
+	uint16_t model_name[20];
+	
+	uint16_t max_rw_multiple;
+	uint16_t reserved48;
+	/** Different meaning for packet device. */
+	uint16_t caps;
+	uint16_t reserved50;
+	uint16_t pio_timing;
+	uint16_t dma_timing;
+	
+	uint16_t validity;
+	uint16_t cur_cyl;
+	uint16_t cur_heads;
+	uint16_t cur_sectors;
+	uint16_t cur_capacity0;
+	uint16_t cur_capacity1;
+	uint16_t mss;
+	uint16_t total_lba28_0;
+	uint16_t total_lba28_1;
+	uint16_t sw_dma;
+	uint16_t mw_dma;
+	uint16_t pio_modes;
+	uint16_t min_mw_dma_cycle;
+	uint16_t rec_mw_dma_cycle;
+	uint16_t min_raw_pio_cycle;
+	uint16_t min_iordy_pio_cycle;
+	
+	uint16_t reserved69;
+	uint16_t reserved70;
+	uint16_t reserved71;
+	uint16_t reserved72;
+	uint16_t reserved73;
+	uint16_t reserved74;
+	
+	uint16_t queue_depth;
+	/** SATA capatibilities - different meaning for packet device. */
+	uint16_t sata_cap;
+	/** SATA additional capatibilities - different meaning for packet device. */
+	uint16_t sata_cap2;
+	uint16_t reserved78[1 + 79 - 78];
+	uint16_t version_maj;
+	uint16_t version_min;
+	uint16_t cmd_set0;
+	uint16_t cmd_set1;
+	uint16_t csf_sup_ext;
+	uint16_t csf_enabled0;
+	uint16_t csf_enabled1;
+	uint16_t csf_default;
+	uint16_t udma;
+	
+	uint16_t reserved89[1 + 99 - 89];
+	
+	/* Total number of blocks in LBA-48 addressing. */
+	uint16_t total_lba48_0;
+	uint16_t total_lba48_1;
+	uint16_t total_lba48_2;
+	uint16_t total_lba48_3;
+	
+	/* Note: more fields are defined in ATA/ATAPI-7. */
+	uint16_t reserved104[1 + 127 - 104];
+	uint16_t _vs128[1 + 159 - 128];
+	uint16_t reserved160[1 + 255 - 160];
+} identify_data_t;
+
+/** Capability bits for register device. */
+enum ata_regdev_caps {
+	rd_cap_iordy = 0x0800,
+	rd_cap_iordy_cbd = 0x0400,
+	rd_cap_lba = 0x0200,
+	rd_cap_dma = 0x0100
+};
+
+/** Bits of @c identify_data_t.cmd_set1. */
+enum ata_cs1 {
+	/** 48-bit address feature set. */
+	cs1_addr48 = 0x0400
+};
+
+/** SATA capatibilities for not packet device - Serial ATA revision 3_1. */
+enum sata_np_cap {
+	/** Supports READ LOG DMA EXT. */
+	np_cap_log_ext = 0x8000,
+	/** Supports Device Automatic Partial to Slumber transitions. */
+	np_cap_dev_slm = 0x4000,
+	/** Supports Host Automatic Partial to Slumber transitions. */
+	np_cap_host_slm = 0x2000,
+	/** Supports NCQ priority information. */
+	np_cap_ncq_prio = 0x1000,
+	/** Supports Unload while NCQ command outstanding. */
+	np_cap_unload_ncq = 0x0800,
+	/** Supports Phy event counters. */
+	np_cap_phy_ctx = 0x0400,
+	/** Supports recepits of host-initiated interface power management. */
+	np_cap_host_pmngmnt = 0x0200,
+	
+	/** Supports NCQ. */
+	np_cap_ncq = 0x0100,
+	
+	/** Supports SATA 3. */
+	np_cap_sata_3 = 0x0008,
+	/** Supports SATA 2. */
+	np_cap_sata_2 = 0x0004,
+	/** Supports SATA 1. */
+	np_cap_sata_1 = 0x0002
+};
+
+/** SATA capatibilities for packet device - Serial ATA revision 3_1. */
+enum sata_pt_cap {
+	/** Supports READ LOG DMA EXT. */
+	pt_cap_log_ext = 0x8000,
+	/** Supports Device Automatic Partial to Slumber transitions. */
+	pt_cap_dev_slm = 0x4000,
+	/** Supports Host Automatic Partial to Slumber transitions. */
+	pt_cap_host_slm = 0x2000,
+	/** Supports Phy event counters. */
+	pt_cap_phy_ctx = 0x0400,
+	/** Supports recepits of host-initiated interface power management. */
+	pt_cap_host_pmngmnt = 0x0200,
+	
+	/** Supports SATA 3. */
+	pt_cap_sat_3 = 0x0008,
+	/** Supports SATA 2. */
+	pt_cap_sat_2 = 0x0004,
+	/** Supports SATA 1. */
+	pt_cap_sat_1 = 0x0002
+};
+
+#endif
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ uspace/lib/c/Makefile	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -71,4 +71,5 @@
 	generic/device/nic.c \
 	generic/device/pci.c \
+	generic/device/ahci.c \
 	generic/elf/elf_load.c \
 	generic/event.c \
Index: uspace/lib/c/generic/device/ahci.c
===================================================================
--- uspace/lib/c/generic/device/ahci.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/lib/c/generic/device/ahci.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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
+ */
+
+#include <ipc/dev_iface.h>
+#include <assert.h>
+#include <device/ahci.h>
+#include <errno.h>
+#include <async.h>
+#include <ipc/services.h>
+#include <stdio.h>
+#include <as.h>
+
+typedef enum {
+	IPC_M_AHCI_GET_SATA_DEVICE_NAME,
+	IPC_M_AHCI_GET_NUM_BLOCKS,
+	IPC_M_AHCI_GET_BLOCK_SIZE,
+	IPC_M_AHCI_READ_BLOCKS,
+	IPC_M_AHCI_WRITE_BLOCKS,
+} ahci_iface_funcs_t;
+
+#define MAX_NAME_LENGTH  1024
+
+#define LO(ptr) \
+	((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff))
+
+#define HI(ptr) \
+	((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) >> 32))
+
+async_sess_t* ahci_get_sess(devman_handle_t funh, char **name)
+{
+	// FIXME: Use a better way than substring match
+	
+	*name = NULL;
+	
+	char devn[MAX_NAME_LENGTH];
+	int rc = devman_fun_get_name(funh, devn, MAX_NAME_LENGTH);
+	if (rc != EOK)
+		return NULL;
+	
+	size_t devn_size = str_size(devn);
+	
+	if ((devn_size > 5) && (str_lcmp(devn, "ahci_", 5) == 0)) {
+		async_sess_t *sess = devman_device_connect(EXCHANGE_PARALLEL,
+		    funh, IPC_FLAG_BLOCKING);
+		
+		if (sess) {
+			*name = str_dup(devn);
+			return sess;
+		}
+	}
+	
+	return NULL;
+}
+
+int ahci_get_sata_device_name(async_sess_t *sess, size_t sata_dev_name_length,
+    char *sata_dev_name)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	aid_t req = async_send_2(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_GET_SATA_DEVICE_NAME, sata_dev_name_length, NULL);
+	
+	async_data_read_start(exch, sata_dev_name, sata_dev_name_length);
+	
+	sysarg_t rc;
+	async_wait_for(req, &rc);
+	
+	return rc;
+}
+
+int ahci_get_num_blocks(async_sess_t *sess, uint64_t *blocks)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	sysarg_t blocks_hi;
+	sysarg_t blocks_lo;
+	int rc = async_req_1_2(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_GET_NUM_BLOCKS, &blocks_hi, &blocks_lo);
+	
+	async_exchange_end(exch);
+	
+	if (rc == EOK) {
+		*blocks = (((uint64_t) blocks_hi) << 32)
+		    | (((uint64_t) blocks_lo) & 0xffffffff);
+	}
+	
+	return rc;
+}
+
+int ahci_get_block_size(async_sess_t *sess, size_t *blocks_size)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	sysarg_t bs;
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_GET_BLOCK_SIZE, &bs);
+	
+	async_exchange_end(exch);
+	
+	if (rc == EOK)
+		*blocks_size = (size_t) bs;
+	
+	return rc;
+}
+
+int ahci_read_blocks(async_sess_t *sess, uint64_t blocknum, size_t count,
+    void *buf)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	aid_t req;
+	req = async_send_4(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_READ_BLOCKS, HI(blocknum),  LO(blocknum), count, NULL);
+	
+	async_share_out_start(exch, buf, AS_AREA_READ | AS_AREA_WRITE);
+	
+	async_exchange_end(exch);
+	
+	sysarg_t rc;
+	async_wait_for(req, &rc);
+	
+	return rc;
+}
+
+int ahci_write_blocks(async_sess_t *sess, uint64_t blocknum, size_t count,
+    void* buf)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	aid_t req = async_send_4(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_WRITE_BLOCKS, HI(blocknum),  LO(blocknum), count, NULL);
+	
+	async_share_out_start(exch, buf, AS_AREA_READ | AS_AREA_WRITE);
+	
+	async_exchange_end(exch);
+	
+	sysarg_t rc;
+	async_wait_for(req, &rc);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/device/ahci.h
===================================================================
--- uspace/lib/c/include/device/ahci.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/lib/c/include/device/ahci.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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 AHCI interface definition.
+ */
+
+#ifndef LIBC_DEVICE_AHCI_H_
+#define LIBC_DEVICE_AHCI_H_
+
+#include <async.h>
+#include <devman.h>
+
+extern async_sess_t* ahci_get_sess(devman_handle_t, char **);
+
+extern int ahci_get_sata_device_name(async_sess_t *, size_t, char *);
+extern int ahci_get_num_blocks(async_sess_t *, uint64_t *);
+extern int ahci_get_block_size(async_sess_t *, size_t *);
+extern int ahci_read_blocks(async_sess_t *, uint64_t, size_t, void *);
+extern int ahci_write_blocks(async_sess_t *, uint64_t, size_t, void *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -57,4 +57,6 @@
 	/** Interface provided by USB HID devices. */
 	USBHID_DEV_IFACE,
+	/** Interface provided by AHCI devices. */
+	AHCI_DEV_IFACE,
 
 	DEV_IFACE_MAX
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ uspace/lib/drv/Makefile	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -46,5 +46,6 @@
 	generic/remote_pci.c \
 	generic/remote_usbhc.c \
-	generic/remote_usbhid.c
+	generic/remote_usbhid.c \
+	generic/remote_ahci.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ uspace/lib/drv/generic/dev_iface.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -48,4 +48,5 @@
 #include "remote_audio_mixer.h"
 #include "remote_audio_pcm.h"
+#include "remote_ahci.h"
 
 static const iface_dipatch_table_t remote_ifaces = {
@@ -60,4 +61,5 @@
 		[USBHC_DEV_IFACE] = &remote_usbhc_iface,
 		[USBHID_DEV_IFACE] = &remote_usbhid_iface,
+		[AHCI_DEV_IFACE] = &remote_ahci_iface,
 	}
 };
Index: uspace/lib/drv/generic/remote_ahci.c
===================================================================
--- uspace/lib/drv/generic/remote_ahci.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/lib/drv/generic/remote_ahci.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,208 @@
+/*
+  * Copyright (c) 2012 Petr Jerman
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <stdio.h>
+#include "ahci_iface.h"
+#include "ddf/driver.h"
+
+typedef enum {
+	IPC_M_AHCI_GET_SATA_DEVICE_NAME,
+	IPC_M_AHCI_GET_NUM_BLOCKS,
+	IPC_M_AHCI_GET_BLOCK_SIZE,
+	IPC_M_AHCI_READ_BLOCKS,
+	IPC_M_AHCI_WRITE_BLOCKS
+} ahci_iface_funcs_t;
+
+#define LO(ptr) \
+	((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff))
+
+#define HI(ptr) \
+	((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) >> 32))
+
+static void remote_ahci_get_sata_device_name(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+static void remote_ahci_get_num_blocks(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+static void remote_ahci_get_block_size(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+static void remote_ahci_read_blocks(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+static void remote_ahci_write_blocks(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+
+/** Remote AHCI interface operations. */
+static remote_iface_func_ptr_t remote_ahci_iface_ops [] = {
+	[IPC_M_AHCI_GET_SATA_DEVICE_NAME] = remote_ahci_get_sata_device_name,
+	[IPC_M_AHCI_GET_NUM_BLOCKS] = remote_ahci_get_num_blocks,
+	[IPC_M_AHCI_GET_BLOCK_SIZE] = remote_ahci_get_block_size,
+	[IPC_M_AHCI_READ_BLOCKS] = remote_ahci_read_blocks,
+	[IPC_M_AHCI_WRITE_BLOCKS] = remote_ahci_write_blocks
+};
+
+/** Remote AHCI interface structure.
+ */
+remote_iface_t remote_ahci_iface = {
+	.method_count = sizeof(remote_ahci_iface_ops) /
+	    sizeof(remote_ahci_iface_ops[0]),
+	.methods = remote_ahci_iface_ops
+};
+
+void remote_ahci_get_sata_device_name(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
+	
+	if (ahci_iface->get_sata_device_name == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	const size_t sata_dev_name_length =
+	    (size_t) DEV_IPC_GET_ARG1(*call);
+	
+	char* sata_dev_name = malloc(sata_dev_name_length);
+	
+	const int ret = ahci_iface->get_sata_device_name(fun,
+	    sata_dev_name_length, sata_dev_name);
+	
+	size_t real_size;
+	ipc_callid_t cid;
+	if ((async_data_read_receive(&cid, &real_size)) &&
+	    (real_size == sata_dev_name_length))
+		async_data_read_finalize(cid, sata_dev_name, sata_dev_name_length);
+	
+	async_answer_0(callid, ret);
+}
+
+static void remote_ahci_get_num_blocks(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
+	
+	if (ahci_iface->get_num_blocks == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint64_t blocks;
+	const int ret = ahci_iface->get_num_blocks(fun, &blocks);
+	
+	if (ret != EOK)
+		async_answer_0(callid, ret);
+	else
+		async_answer_2(callid, EOK, HI(blocks), LO(blocks));
+}
+
+static void remote_ahci_get_block_size(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
+	
+	if (ahci_iface->get_block_size == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t blocks;
+	const int ret = ahci_iface->get_block_size(fun, &blocks);
+	
+	if (ret != EOK)
+		async_answer_0(callid, ret);
+	else
+		async_answer_1(callid, EOK, blocks);
+}
+
+void remote_ahci_read_blocks(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
+	
+	if (ahci_iface->read_blocks == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t maxblock_size;
+	unsigned int flags;
+	
+	ipc_callid_t cid;
+	async_share_out_receive(&cid, &maxblock_size, &flags);
+	
+	void *buf;
+	async_share_out_finalize(cid, &buf);
+	
+	const uint64_t blocknum =
+	    (((uint64_t) (DEV_IPC_GET_ARG1(*call))) << 32) |
+	    (((uint64_t) (DEV_IPC_GET_ARG2(*call))) & 0xffffffff);
+	const size_t cnt = (size_t) DEV_IPC_GET_ARG3(*call);
+	
+	const int ret = ahci_iface->read_blocks(fun, blocknum, cnt, buf);
+	
+	async_answer_0(callid, ret);
+}
+
+void remote_ahci_write_blocks(ddf_fun_t *fun, void *iface, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface;
+	
+	if (ahci_iface->read_blocks == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t maxblock_size;
+	unsigned int flags;
+	
+	ipc_callid_t cid;
+	async_share_out_receive(&cid, &maxblock_size, &flags);
+	
+	void *buf;
+	async_share_out_finalize(cid, &buf);
+	
+	const uint64_t blocknum =
+	    (((uint64_t)(DEV_IPC_GET_ARG1(*call))) << 32) |
+	    (((uint64_t)(DEV_IPC_GET_ARG2(*call))) & 0xffffffff);
+	const size_t cnt = (size_t) DEV_IPC_GET_ARG3(*call);
+	
+	const int ret = ahci_iface->write_blocks(fun, blocknum, cnt, buf);
+	
+	async_answer_0(callid, ret);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/ahci_iface.h
===================================================================
--- uspace/lib/drv/include/ahci_iface.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/lib/drv/include/ahci_iface.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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 libdrv
+ * @addtogroup ahci
+ * @{
+ */
+/** @file
+ * @brief AHCI interface definition.
+ */
+
+#ifndef LIBDRV_AHCI_IFACE_H_
+#define LIBDRV_AHCI_IFACE_H_
+
+#include "ddf/driver.h"
+#include <async.h>
+
+/** AHCI device communication interface. */
+typedef struct {
+	int (*get_sata_device_name)(ddf_fun_t *, size_t, char *);
+	int (*get_num_blocks)(ddf_fun_t *, uint64_t *);
+	int (*get_block_size)(ddf_fun_t *, size_t *);
+	int (*read_blocks)(ddf_fun_t *, uint64_t, size_t, void *);
+	int (*write_blocks)(ddf_fun_t *, uint64_t, size_t, void *);
+} ahci_iface_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/remote_ahci.h
===================================================================
--- uspace/lib/drv/include/remote_ahci.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/lib/drv/include/remote_ahci.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_AHCI_H_
+#define LIBDRV_REMOTE_AHCI_H_
+
+extern remote_iface_t remote_ahci_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/bd/sata_bd/Makefile
===================================================================
--- uspace/srv/bd/sata_bd/Makefile	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/srv/bd/sata_bd/Makefile	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2012 Petr Jerman
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+BINARY = sata_bd
+
+SOURCES = \
+	sata_bd.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/bd/sata_bd/sata_bd.c
===================================================================
--- uspace/srv/bd/sata_bd/sata_bd.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/srv/bd/sata_bd/sata_bd.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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 bd
+ * @{
+ */
+
+/**
+ * @file
+ * @brief SATA disk driver
+ *
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ipc/bd.h>
+#include <str.h>
+#include <loc.h>
+#include <macros.h>
+
+#include <device/ahci.h>
+#include "sata_bd.h"
+
+#define NAME       "sata_bd"
+#define NAMESPACE  "bd"
+
+#define MAXDISKS 256
+
+static sata_dev_t disk[MAXDISKS];
+static int disk_count;
+
+static int scan_device_tree(devman_handle_t funh)
+{
+	devman_handle_t devh;
+	devman_handle_t *cfuns;
+	size_t count, i;
+	int rc;
+		
+	/* If device is SATA, add device to the disk array. */
+	disk[disk_count].sess = ahci_get_sess(funh, &disk[disk_count].dev_name);
+	if(disk[disk_count].sess != NULL) {
+		
+		ahci_get_sata_device_name(disk[disk_count].sess,
+		    SATA_DEV_NAME_LENGTH, disk[disk_count].sata_dev_name);
+		
+		ahci_get_block_size(disk[disk_count].sess,
+		    &disk[disk_count].block_size);
+		
+		ahci_get_num_blocks(disk[disk_count].sess, &disk[disk_count].blocks);
+				
+		printf("Device %s - %s , blocks: %lu, block_size: %lu\n", 
+		    disk[disk_count].dev_name, disk[disk_count].sata_dev_name,
+			    (long unsigned int) disk[disk_count].blocks,
+				(long unsigned int) disk[disk_count].block_size);
+
+		++disk_count;
+	}
+	
+	/* search children */
+	rc = devman_fun_get_child(funh, &devh);
+	if (rc == ENOENT)
+		return EOK;
+
+	if (rc != EOK) {
+		printf(NAME ": Failed getting child device for function %s.\n", "xxx");
+		return rc;
+	}
+
+	rc = devman_dev_get_functions(devh, &cfuns, &count);
+	if (rc != EOK) {
+		printf(NAME ": Failed getting list of functions for device %s.\n",
+		    "xxx");
+		return rc;
+	}
+
+	for (i = 0; i < count; i++)
+		scan_device_tree(cfuns[i]);
+
+	free(cfuns);
+	return EOK;
+}
+
+/** Find sata devices in device tree from root. */
+static int get_sata_disks()
+{
+	devman_handle_t root_fun;
+	int rc;
+	
+	disk_count = 0;
+
+	rc = devman_fun_get_handle("/", &root_fun, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving root function.\n");
+		return EIO;
+	}
+	
+	scan_device_tree(root_fun);
+	
+	return EOK;
+}
+
+/** Block device connection handler. */
+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;
+
+	/* Get the device service ID. */
+	dsid = IPC_GET_ARG1(*icall);
+
+	/* Determine which disk device is the client connecting to. */
+	disk_id = -1;
+	for (i = 0; i < MAXDISKS; i++)
+		if (disk[i].service_id == dsid)
+			disk_id = i;
+
+	if (disk_id < 0) {
+		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 == (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);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int rc;
+	
+	async_set_client_connection(sata_bd_connection);
+	rc = loc_server_register(NAME);
+	if (rc < 0) {
+		printf(NAME ": Unable to register driver.\n");
+		return rc;
+	}
+	
+	rc = get_sata_disks();
+	if (rc != EOK) {
+		return rc;
+	}
+
+	for(int i=0; i < disk_count; i++) {
+		char name[1024];
+		snprintf(name, 1024, "%s/%s", NAMESPACE, disk[i].dev_name);
+		rc = loc_service_register(name, &disk[i].service_id);
+		if (rc != EOK) {
+			printf(NAME ": Unable to register device %s.\n", name);
+			return rc;
+		}
+	}
+		
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+
+	/* Not reached */
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/bd/sata_bd/sata_bd.h
===================================================================
--- uspace/srv/bd/sata_bd/sata_bd.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
+++ uspace/srv/bd/sata_bd/sata_bd.h	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * 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 bd
+ * @{
+ */
+/** @file SATA block device driver definitions.
+ */
+
+#ifndef __SATA_BD_H__
+#define __SATA_BD_H__
+
+#define SATA_DEV_NAME_LENGTH 256
+
+#include <sys/types.h>
+#include <loc.h>
+
+/** SATA Device. */
+typedef struct {
+	/** 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; 
+	/** Loc service id. */
+	service_id_t service_id;
+	/** Number of blocks. */
+	uint64_t blocks; 
+	/** Size of block. */
+	size_t block_size; 
+} sata_dev_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ uspace/srv/devman/main.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -419,5 +419,7 @@
 	
 	/* Check that function with same name is not there already. */
-	if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) {
+	fun_node_t *tfun = find_fun_node_in_device(tree, pdev, fun_name);
+	if (tfun) {
+		fun_del_ref(tfun);	/* drop the new unwanted reference */
 		fibril_rwlock_write_unlock(&tree->rwlock);
 		dev_del_ref(pdev);
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 1f7da3b6b3615f4e718b66c7dd10fe063e689e6f)
+++ uspace/srv/hid/console/console.c	(revision 1bebadeef8c0e20e4858c16afc1cb5411a16aeaa)
@@ -76,7 +76,11 @@
 } console_state_t;
 
+#define UTF8_CHAR_BUFFER_SIZE (STR_BOUNDS(1) + 1)
+
 typedef struct {
 	atomic_t refcnt;           /**< Connection reference count */
 	prodcons_t input_pc;       /**< Incoming keyboard events */
+	char char_remains[UTF8_CHAR_BUFFER_SIZE]; /**< Not yet sent bytes of last char event. */
+	size_t char_remains_len;   /**< Number of not yet sent bytes. */
 	
 	fibril_mutex_t mtx;        /**< Lock protecting mutable fields */
@@ -613,14 +617,37 @@
 	
 	size_t pos = 0;
+	
+	/*
+	 * Read input from keyboard and copy it to the buffer.
+	 * We need to handle situation when wchar is split by 2 following
+	 * reads.
+	 */
 	while (pos < size) {
-		link_t *link = prodcons_consume(&cons->input_pc);
-		kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-		
-		if (event->type == KEY_PRESS) {
-			buf[pos] = event->c;
+		/* Copy to the buffer remaining characters. */
+		while ((pos < size) && (cons->char_remains_len > 0)) {
+			buf[pos] = cons->char_remains[0];
 			pos++;
-		}
-		
-		free(event);
+			
+			/* Unshift the array. */
+			for (size_t i = 1; i < cons->char_remains_len; i++)
+				cons->char_remains[i - 1] = cons->char_remains[i];
+			
+			cons->char_remains_len--;
+		}
+		
+		/* Still not enough? Then get another key from the queue. */
+		if (pos < size) {
+			link_t *link = prodcons_consume(&cons->input_pc);
+			kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
+			
+			/* Accept key presses of printable chars only. */
+			if ((event->type == KEY_PRESS) && (event->c != 0)) {
+				wchar_t tmp[2] = { event->c, 0 };
+				wstr_to_str(cons->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
+				cons->char_remains_len = str_size(cons->char_remains);
+			}
+			
+			free(event);
+		}
 	}
 	
@@ -930,4 +957,5 @@
 		fibril_mutex_initialize(&consoles[i].mtx);
 		prodcons_initialize(&consoles[i].input_pc);
+		consoles[i].char_remains_len = 0;
 		
 		if (graphics_state == GRAPHICS_FULL) {
