Index: testsuites/libtests/ChangeLog
===================================================================
--- testsuites/libtests/ChangeLog	(revision c4c8efd02782845db7658b1885a6e509ca15a4f1)
+++ testsuites/libtests/ChangeLog	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -1,2 +1,23 @@
+2010-01-18	Sebastian Huber <Sebastian.Huber@embedded-brains.de>
+
+	* block09/block09.doc, block09/init.c, block09/.cvsignore,
+	block09/block09.scn, block09/Makefile.am: New files.
+	* configure.ac, Makefile.am: Update for new files.
+	* block05/block05.doc: Update for new state transitions.
+	* block05/init.c, block06/init.c: Update for block device API change.
+
+2010-01-18	Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+
+	* block08/bdbuf_test1_1.c, block08/bdbuf_test1_2.c,
+	block08/bdbuf_test1_3.c, block08/bdbuf_test1_4.c,
+	block08/bdbuf_test1_5.c, block08/bdbuf_test2_1.c,
+	block08/bdbuf_test2_2.c, block08/bdbuf_test3_1.c,
+	block08/bdbuf_test3_2.c, block08/bdbuf_test3_3.c,
+	block08/bdbuf_test4_1.c, block08/bdbuf_test4_2.c,
+	block08/bdbuf_test4_3.c, block08/bdbuf_tests.c, block08/bdbuf_tests.h,
+	block08/block08.doc, block08/block08.scn, block08/.cvsignore,
+	block08/init.c, block08/Makefile.am, block08/system.h,
+	block08/test_disk.c: New files.
+
 2009-12-28	Aanjhan Ranganathan <aanjhan@gmail.com>
 
Index: testsuites/libtests/Makefile.am
===================================================================
--- testsuites/libtests/Makefile.am	(revision c4c8efd02782845db7658b1885a6e509ca15a4f1)
+++ testsuites/libtests/Makefile.am	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -8,5 +8,5 @@
     monitor02 rtmonuse stackchk stackchk01 termios termios01 termios02 \
     rtems++ tztest block01 block02 block03 block04 block05 block06 block07 \
-    stringto01
+    block08 block09 stringto01
 SUBDIRS += POSIX
 
Index: testsuites/libtests/block05/init.c
===================================================================
--- testsuites/libtests/block05/init.c	(revision c4c8efd02782845db7658b1885a6e509ca15a4f1)
+++ testsuites/libtests/block05/init.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -369,5 +369,5 @@
       case RTEMS_BLKDEV_REQ_READ:
       case RTEMS_BLKDEV_REQ_WRITE:
-        r->req_done(r->done_arg, RTEMS_SUCCESSFUL, 0);
+        r->req_done(r->done_arg, RTEMS_SUCCESSFUL);
         return 0;
       default:
Index: testsuites/libtests/block06/init.c
===================================================================
--- testsuites/libtests/block06/init.c	(revision c4c8efd02782845db7658b1885a6e509ca15a4f1)
+++ testsuites/libtests/block06/init.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -502,5 +502,5 @@
               }
 
-              r->req_done (r->done_arg, RTEMS_SUCCESSFUL, 0);
+              r->req_done (r->done_arg, RTEMS_SUCCESSFUL);
             }
             bdbuf_disk_ioctl_leave (bdd, r->bufnum);
@@ -510,5 +510,5 @@
             if (!bdbuf_disk_ioctl_process (bdd, r))
               errno = EIO;
-            r->req_done (r->done_arg, RTEMS_SUCCESSFUL, 0);
+            r->req_done (r->done_arg, RTEMS_SUCCESSFUL);
             bdbuf_disk_ioctl_leave (bdd, r->bufnum);
             break;
Index: testsuites/libtests/block08/Makefile.am
===================================================================
--- testsuites/libtests/block08/Makefile.am	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/Makefile.am	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,50 @@
+##
+## Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+## Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+##
+## The license and distribution terms for this file may be
+## found in the file LICENSE in this distribution or at
+## http://www.rtems.com/license/LICENSE.
+## $Id$
+##
+
+MANAGERS = all
+
+rtems_tests_PROGRAMS = block08
+block08_SOURCES = init.c               \
+                       system.h        \
+                       bdbuf_tests.c   \
+	               bdbuf_tests.h   \
+		       test_disk.c     \
+		       bdbuf_test1_1.c \
+                       bdbuf_test1_2.c \
+                       bdbuf_test1_3.c \
+                       bdbuf_test1_4.c \
+                       bdbuf_test1_5.c \
+                       bdbuf_test2_1.c \
+                       bdbuf_test2_2.c \
+                       bdbuf_test3_1.c \
+                       bdbuf_test3_2.c \
+                       bdbuf_test3_3.c \
+                       bdbuf_test4_1.c \
+                       bdbuf_test4_2.c \
+                       bdbuf_test4_3.c
+
+dist_rtems_tests_DATA = block08.scn block08.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+block08_LDADD = $(MANAGERS_NOT_WANTED:%=$(PROJECT_LIB)/no-%.rel)
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(block08_OBJECTS) $(block08_LDADD)
+LINK_LIBS = $(block08_LDLIBS)
+
+block08$(EXEEXT): $(block08_OBJECTS) $(block08_DEPENDENCIES)
+	@rm -f block08$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
Index: testsuites/libtests/block08/bdbuf_test1_1.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test1_1.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test1_1.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,146 @@
+/*! @file
+ * @brief Check the behaviour of rtems_bdbuf_read() function 
+ * with different reports from disk device driver.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read() function and return 0 from disk device 
+ *    driver ioctl() function, and the result of asynchronous read
+ *    complete notification is successful.
+ * -# Check that rtems_bdbuf_read() returns RTEMS_SUCCESSFUL and
+ *    provides buffer descriptor.
+ * -# Call rtems_bdbuf_read() function and return -1 from disk device
+ *    driver ioctl() function (there will be no asynchronous read 
+ *    complete notification).
+ * -# Check that rtems_bdbuf_read() returns RTEMS_IO_ERROR.
+ * -# Call rtems_bdbuf_read() function and return 0 from disk device
+ *    driver ioctl() function, but the result of asynchronous read 
+ *    complete notification is faulty (with some erroneous status).
+ * -# Check that rtems_bdbuf_read() returns that status and does not
+ *    return buffer descriptor.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test1_1_thread1(rtems_task_argument arg);
+
+#define TEST_BLK_NUM 10
+
+void
+bdbuf_test1_1_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 1.1");
+
+    /*
+     * Create working thread that will call rtems_bdbuf_read() function.
+     */
+    START_THREAD(1, bdbuf_test1_1_thread1);
+    
+    /*
+     * Step 1:
+     * Check that rtems_bdbuf_read() returns RTEMS_SUCCESSFUL
+     * when device driver returns 0 from ioctl() call and
+     * return RTEMS_SUCCESSFUL status in asynchronous
+     * callback notification.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("2");
+
+    CONTINUE_THREAD(1);
+
+    /*
+     * Step 3:
+     * Check that rtems_bdbuf_read() returns RTEMS_IO_ERROR
+     * return code, when device driver returns -1 from ioctl() call.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(-1, EFAULT, RTEMS_SUCCESSFUL, 0);
+
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("4");
+
+    CONTINUE_THREAD(1);
+
+    /*
+     * Step 5:
+     * Check that rtems_bdbuf_read() returns status obtained
+     * from device driver via asynchonous notification.
+     * On this step device driver returns 0 from ioctl() call,
+     * but notification callback is called with RTEMS_NO_MEMORY status.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_NO_MEMORY, EFAULT);
+
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("6");
+
+    CONTINUE_THREAD(1);
+
+    TEST_END();
+}
+
+
+static rtems_task
+bdbuf_test1_1_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd1 = NULL;
+    rtems_bdbuf_buffer *bd2 = NULL;
+
+    /*
+     * Step 1-2:
+     * Successful read operation.
+     */
+    rc = rtems_bdbuf_read(test_dev, 0, &bd1);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    rc = rtems_bdbuf_release(bd1);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    /*
+     * Step 3-4:
+     * Read operation fails with RTEMS_IO_ERROR code.
+     * The function shall not update user pointer.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd2);
+    if (rc != RTEMS_IO_ERROR || bd2 != NULL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    /*
+     * Step 5-6:
+     * Read operation fails with RTEMS_NO_MEMORY code.
+     * The function shall not update user pointer.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd2);
+    if (rc != RTEMS_NO_MEMORY || bd2 != NULL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    THREAD_END();
+}
+
Index: testsuites/libtests/block08/bdbuf_test1_2.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test1_2.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test1_2.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,161 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_read() handles two readers waiting
+ * for a buffer with the same block number in cases when disk device
+ * driver reports failure in read complete notification.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read() function in thread #1 and block on 
+ *    waiting for read complete notification.
+ * -# Call rtems_bdbuf_read() function in thread #2 for the same
+ *    block number. As the result it blocks on this read as well
+ *    (but it will block on transfer semaphore).
+ * -# Disk device reports an error in read complete notification.
+ *    As the result an error is returned from rtems_bdbuf_read() in
+ *    thread #1.
+ * -# rtems_bdbuf_read() called in thread #2 should try to re-read
+ *    data again so disk device ioctl() function is called again for
+ *    this block number.
+ * -# Disk device reports an error in read complete notification.
+ *    As the result an error is returned from rtems_bdbuf_read()
+ *    in thread #2.
+ * .
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test1_2_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test1_2_thread2(rtems_task_argument arg);
+
+#define TEST_BLK_NUM 20
+
+void
+bdbuf_test1_2_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 1.2");
+
+    START_THREAD(1, bdbuf_test1_2_thread1);
+    START_THREAD(2, bdbuf_test1_2_thread2);
+
+    /*
+     * Step 1:
+     * Thread #1 calls rtems_bdbuf_read() and we block
+     * this thread on data transfer operation.
+     */
+    WAIT_DRV_MSG(&msg);
+
+    /*
+     * Step 2:
+     * Thread #2 calls rtems_bdbuf_read() for the same 
+     * block number, as the result it shall block waiting
+     * on buffer state change.
+     */
+    CONTINUE_THREAD(2);
+
+    /* Make sure thread #2 managed to block on the buffer. */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 3:
+     * Unblock thread #1 by reporting data transfer result.
+     */
+    SEND_DRV_MSG(0, 0, RTEMS_NO_MEMORY, EFAULT);
+
+    /*
+     * Wait for sync from thread #1.
+     */
+    WAIT_THREAD_SYNC(1);
+    CONTINUE_THREAD(1);
+    TEST_CHECK_RESULT("3");
+
+    /*
+     * Step 4:
+     * For thread #2 bdbuf shall try to re-read data.
+     * As the result we will get read call to device driver.
+     */
+    WAIT_DRV_MSG(&msg);
+    
+    /* Check that thread #2 is still blocked */
+    CHECK_THREAD_BLOCKED(2);
+    /*
+     * Step 5:
+     * Report an error again from the driver.
+     */
+    SEND_DRV_MSG(0, 0, RTEMS_NO_MEMORY, EFAULT);
+
+    /*
+     * Wait for sync from thread #2.
+     */
+    WAIT_THREAD_SYNC(2);
+    CONTINUE_THREAD(2);
+    TEST_CHECK_RESULT("5");
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test1_2_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1 - 3:
+     * Try to read blk #N on thread #1
+     * We will block on this read and meanwhile
+     * thread #2 will try to read the same block.
+     * After blocking on read in thread #2, device
+     * driver will notify about an error, and as the
+     * result this call will return an error.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_NO_MEMORY || bd != NULL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test1_2_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * Try to read block #N. Right now thread #1 is waiting
+     * on data transfer operation, so we will block here as well.
+     *
+     * Step 4:
+     * Due to the fact that thread #1 failed to read required block
+     * number, bdbuf library should ask for re-read data again.
+     * But main test task will agin tell device driver to return
+     * RTEMS_NO_MEMORY data transfer result.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_NO_MEMORY || bd != NULL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(2);
+
+    THREAD_END();
+}
+
Index: testsuites/libtests/block08/bdbuf_test1_3.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test1_3.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test1_3.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,177 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_read() handles two readers waiting
+ * for a buffer with the same block number in cases when disk device 
+ * driver reports failure in read complete notification.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read() function in thread #1 and block on
+ *    waiting for read complete notification.
+ * -# Call rtems_bdbuf_read() function in thread #2 for the same block
+ *    number. As the result it blocks on this read as well (but it will
+ *    block on transfer semaphore).
+ * -# Disk device reports an error in read complete notification.
+ *    As the result an error is returned from rtems_bdbuf_read()
+ *    in thread #1.
+ * -# rtems_bdbuf_read() called in thread #2 should try to re-read data
+ *    again so disk device ioctl() function is called again for this
+ *    block number.
+ * -# This time disk device reports success in read complete notification.
+ *    As the result rtems_bdbuf_read() in thread #2 shall return 
+ *    RTEMS_SUCCESSFUL and provide buffer descriptor.
+ * -# Call rtems_bdbuf_release() function in thread #2.
+ * .
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test1_3_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test1_3_thread2(rtems_task_argument arg);
+
+#define TEST_BLK_NUM 30
+
+void
+bdbuf_test1_3_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 1.3");
+
+    START_THREAD(1, bdbuf_test1_3_thread1);
+    START_THREAD(2, bdbuf_test1_3_thread2);
+
+    /*
+     * Step 1:
+     * Thread #1 calls rtems_bdbuf_read() and we block
+     * this thread on data transfer operation.
+     */
+    WAIT_DRV_MSG(&msg);
+
+    /*
+     * Step 2:
+     * Thread #2 calls rtems_bdbuf_read() for the same 
+     * block number, as the result it shall block waiting
+     * on buffer state change.
+     */
+    CONTINUE_THREAD(2);
+
+    /* Make sure thread #2 managed to block on the buffer. */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 3:
+     * Unblock thread #1 by reporting erroneous data transfer result.
+     */
+    SEND_DRV_MSG(0, 0, RTEMS_NO_MEMORY, EFAULT);
+
+    /*
+     * Wait for sync from thread #1.
+     */
+    WAIT_THREAD_SYNC(1);
+    CONTINUE_THREAD(1);
+    TEST_CHECK_RESULT("3");
+
+    /* Check thread #2 is still blocked */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 4:
+     * For thread #2 bdbuf shall try to re-read data.
+     * As the result we will get read call to device driver.
+     */
+    WAIT_DRV_MSG(&msg);
+
+    /*
+     * Step 5:
+     * This time report success from the driver and
+     * rtems_bdbuf_read() in thread #2 shall return
+     * RTEMS_SUCCESSFUL.
+     */
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Wait for sync from thread #2.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("5");
+
+    /*
+     * Step 6:
+     * Release buffer in thread #2
+     */
+    CONTINUE_THREAD(2);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test1_3_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1 - 3:
+     * Try to read blk #N on thread #1
+     * We will block on this read and meanwhile
+     * thread #2 will try to read the same block.
+     * After blocking on read in thread #2, device
+     * driver will notify about an error, and as the
+     * result this call will return an error.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_NO_MEMORY || bd != NULL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test1_3_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * Try to read block #N. Right now thread #1 is waiting
+     * on data transfer operation, so we will block here as well.
+     *
+     * Step 4-5:
+     * Due to the fact that thread #1 failed to read required block
+     * number, bdbuf library should ask for re-read data again.
+     * Time time main task will tell driver to report success.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL || bd == NULL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(2);
+
+    /*
+     * Step 6:
+     * Release buffer.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
Index: testsuites/libtests/block08/bdbuf_test1_4.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test1_4.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test1_4.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,179 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_read() handles two readers waiting
+ * for a buffer with the same block number in cases when disk device 
+ * driver reports success in read complete notification.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read() function in thread #1 and block on
+ *    waiting for read complete notification.
+ * -# Call rtems_bdbuf_read() function in thread #2 for the same
+ *    block number. As the result it blocks on this read as well
+ *    (but it will block on transfer semaphore).
+ * -# Disk device reports success in read complete notification.
+ *    As the result rtems_bdbuf_read() function returns RTEMS_SUCCESSFUL
+ *    in thread #1.
+ * -# Thread #1 releases buffer with rtems_bdbuf_release() function.
+ * -# rtems_bdbuf_read() function in thread #2 unlocks and 
+ *    returns RTEMS_SUCCESSFUL.
+ * -# Call rtems_bdbuf_release() function in thread #2.
+ * .
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test1_4_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test1_4_thread2(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM 40
+
+void
+bdbuf_test1_4_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 1.4");
+
+    START_THREAD(1, bdbuf_test1_4_thread1);
+    START_THREAD(2, bdbuf_test1_4_thread2);
+
+    /*
+     * Step 1:
+     * Thread #1 calls rtems_bdbuf_read() and we block
+     * this thread on data transfer operation.
+     */
+    WAIT_DRV_MSG(&msg);
+
+    /*
+     * Step 2:
+     * Thread #2 calls rtems_bdbuf_read() for the same 
+     * block number, as the result it shall block waiting
+     * on buffer state change (waiting on TRANSFER state).
+     */
+    CONTINUE_THREAD(2);
+
+    /* Make sure threads #1 and #2 managed blocked on the buffer. */
+    CHECK_THREAD_BLOCKED(1);
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 3:
+     * Unblock thread #1 by reporting successful data transfer result.
+     */
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Wait for sync from thread #1.
+     */
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("3");
+
+    /* 
+     * Check that thread #2 is still blocked.
+     */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 4:
+     * Thread #1 releases buffer with bdbuf_release() call.
+     */
+    CONTINUE_THREAD(1);
+
+    /*
+     * Step 5:
+     * On buffer release operation, we should have unblock
+     * of thread #2 that is wating on read buffer operation.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("5");
+
+    /*
+     * Step 6:
+     * Thread #2 release buffer.
+     */
+    CONTINUE_THREAD(2);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test1_4_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1 - 3:
+     * Try to read blk #N on thread #1
+     * We will block on this read and meanwhile
+     * thread #2 will try to read the same block.
+     * After blocking on read in thread #2, device
+     * driver will notify successful completion of 
+     * date transfer, and as the result this call 
+     * will return valid buffer.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(1);
+
+    /*
+     * Step 4:
+     * Release buffer returned on the previous step.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test1_4_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * Try to read block #N. Right now thread #1 is waiting
+     * on data transfer operation, so we will block here as well.
+     *
+     * Step 5:
+     * On step 4 thread #1 releases buffer and as the result 
+     * our read operation should finish with success. 
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(2);
+
+    /*
+     * Step 6:
+     * Release buffer returned on the previous step.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+
Index: testsuites/libtests/block08/bdbuf_test1_5.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test1_5.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test1_5.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,146 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_read() handles read request
+ * for a buffer that is owned by an application.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read() function in thread #1 and 
+ *    provide successful read complete notification for this operation.
+ *    As the result rtems_bdbuf_read() returns RTEMS_SUCCESSFUL
+ *    in thread #1.
+ * -# In thread #2 call rtems_bdbuf_read() function for the same
+ *    block number. A buffer for this block is owned by an application
+ *    and as the result thread #2 block on this function.
+ * -# Call rtems_bdbuf_release() function in thread #1 in order to give
+ *    it back under control of bdbuf library.
+ * -# Buffer now is ready to be returned for another application and
+ *    as the result rtems_bdbuf_read() unblocks and returns 
+ *    RTEMS_SUCCESSFUL in thread #2.
+ * -# Call rtems_bdbuf_release() function in thread #2.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test1_5_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test1_5_thread2(rtems_task_argument arg);
+
+#define TEST_BLK_NUM 50
+
+void
+bdbuf_test1_5_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 1.5");
+
+    START_THREAD(1, bdbuf_test1_5_thread1);
+    START_THREAD(2, bdbuf_test1_5_thread2);
+
+    /*
+     * Step 1:
+     * Thread #1 calls rtems_bdbuf_read() and successfully
+     * get requested buffer.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("1");
+    
+    /*
+     * Step 2:
+     * Thread #2 calls rtems_bdbuf_read() and blocks
+     * on this call because thread #1 owns a buffer.
+     */
+    CONTINUE_THREAD(2);
+
+    /* Make sure thread #2 managed to block on a read request. */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 3:
+     * Now thread #1 releases a buffer.
+     */
+    CONTINUE_THREAD(1);
+
+    /*
+     * Step 4:
+     * Thread #2 should unblock now and get the buffer.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("4");
+
+    /*
+     * Step 5:
+     * Thread #2 release buffer.
+     */
+    CONTINUE_THREAD(2);
+    
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test1_5_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1:
+     * read blk #N on thread #1
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(1);
+
+    /*
+     * Step 3:
+     * Release buffer returned on step 1.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test1_5_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * Try to read block #N. Right now thread #1 owns
+     * this buffer, so we will block waiting for buffer.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(2);
+
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
Index: testsuites/libtests/block08/bdbuf_test2_1.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test2_1.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test2_1.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,195 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_read() and rtems_bdbuf_release_modified()
+ * coexist. rtems_bdbuf_read() is blocked when required buffer is being
+ * transferred.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read() function in thread #1 and block on
+ *    waiting for read complete notification.
+ * -# Call rtems_bdbuf_read() function in thread #2 for the same block
+ *    number. As the result it blocks on this read as well
+ *    (but it will block on transfer semaphore).
+ * -# Disk device reports success in read complete notification.
+ *    As the result rtems_bdbuf_read() function retuens RTEMS_SUCCESSFUL
+ *    in thread #1.
+ * -# Thread #1 releases buffer with rtems_bdbuf_release_modified() function.
+ * -# rtems_bdbuf_read() function in thread #2 unlocks and returns
+ *    RTEMS_SUCCESSFUL.
+ * -# Wait swapout period and check that the buffer is not requested to
+ *    be flushed to a disk.
+ * -# Call rtems_bdbuf_release() function in thread #2.
+ * -# Check that this block number is requested for a flush in swapout period.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test2_1_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test2_1_thread2(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM 60
+
+void
+bdbuf_test2_1_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 2.1");
+
+    /*
+     * Create two working threads that will call rtems_bdbuf_read() function.
+     */
+    START_THREAD(1, bdbuf_test2_1_thread1);
+    START_THREAD(2, bdbuf_test2_1_thread2);
+
+    /*
+     * Step 1:
+     * Thread #1 calls rtems_bdbuf_read() and we block
+     * this thread on data transfer operation.
+     */
+    WAIT_DRV_MSG(&msg);
+
+    /*
+     * Step 2:
+     * Thread #2 calls rtems_bdbuf_read() for the same 
+     * block number, as the result it shall block waiting
+     * on buffer state change (waiting on TRANSFER state).
+     */
+    CONTINUE_THREAD(2);
+
+    /* Make sure thread #2 managed to block on the buffer. */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 3:
+     * Unblock thread #1 by reporting successful data transfer result.
+     */
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Wait for sync from thread #1.
+     */
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("3");
+
+    /* Check thread #2 is still blocked */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 4:
+     * Thread #1 releases buffer with bdbuf_release_modified() call.
+     */
+    CONTINUE_THREAD(1);
+
+    /*
+     * Step 5:
+     * On buffer release operation, we should have unblock
+     * of thread #2 that is waiting on read buffer operation.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("5");
+
+   /*
+    * Step 6:
+    * Wait swapout period and check that there is no
+    * request to flush buffer onto a disk.
+    */
+    CHECK_NO_DRV_MSG();
+
+    /*
+     * Step 7:
+     * Thread #2 releases buffer with bdbuf_release() call.
+     */
+    CONTINUE_THREAD(2);
+
+    /*
+     * Step 8:
+     * Check that in swapout interval disk device
+     * driver is requested to flush buffer.
+     */
+    WAIT_DRV_MSG_WR(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test2_1_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1 - 3:
+     * Try to read blk #N on thread #1
+     * We will block on this read and meanwhile
+     * thread #2 will try to read the same block.
+     * After blocking on read in thread #2, device
+     * driver will notify successful completion of 
+     * date transfer, and as the result this call 
+     * will return valid buffer.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(1);
+
+    /*
+     * Step 4:
+     * Release buffer returned on the previous step.
+     */
+    rc = rtems_bdbuf_release_modified(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test2_1_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * Try to read block #N. Right now thread #1 is waiting
+     * on data transfer operation, so we will block here as well.
+     *
+     * Step 5:
+     * On step 4 thread #1 releases buffer and as the result 
+     * our read operation should finish with success. 
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(2);
+
+    /*
+     * Step 7:
+     * Release buffer.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
Index: testsuites/libtests/block08/bdbuf_test2_2.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test2_2.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test2_2.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,196 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_read() and rtems_bdbuf_release_modified()
+ * coexist. rtems_bdbuf_read() is blocked when required buffer is being
+ * transferred.
+ *
+ * The same as Test 2.1, but on step 7 thread #2 calls
+ * rtems_bdbuf_release_modified().
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read() function in thread #1 and block on
+ *    waiting for read complete notification.
+ * -# Call rtems_bdbuf_read() function in thread #2 for 
+ *    the same block number. As the result it blocks on this read
+ *    as well (but it will block on transfer semaphore).
+ * -# Disk device reports success in read complete notification.
+ *    As the result rtems_bdbuf_read() function returns
+ *    RTEMS_SUCCESSFUL in thread #1.
+ * -# Thread #1 releases buffer with rtems_bdbuf_release_modified() function.
+ * -# rtems_bdbuf_read() function in thread #2 unlocks and
+ *    returns RTEMS_SUCCESSFUL.
+ * -# Wait swapout period and check that the buffer is not requested
+ *    to be flushed to a disk.
+ * -# Call rtems_bdbuf_release_modified() function in thread #2.
+ * -# Check that this block number is requested for a flush in swapout period.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test2_2_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test2_2_thread2(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM 70
+
+void
+bdbuf_test2_2_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 2.2");
+
+    START_THREAD(1, bdbuf_test2_2_thread1);
+    START_THREAD(2, bdbuf_test2_2_thread2);
+
+    /*
+     * Step 1:
+     * Thread #1 calls rtems_bdbuf_read() and we block
+     * this thread on data transfer operation.
+     */
+    WAIT_DRV_MSG(&msg);
+
+    /*
+     * Step 2:
+     * Thread #2 calls rtems_bdbuf_read() for the same 
+     * block number, as the result it shall block waiting
+     * on buffer state change (waiting on TRANSFER state).
+     */
+    CONTINUE_THREAD(2);
+
+    /* Make sure thread #2 managed to block on the buffer. */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 3:
+     * Unblock thread #1 by reporting successful data transfer result.
+     */
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Wait for sync from thread #1.
+     */
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("3");
+
+    /* Check thread #2 is still blocked */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 4:
+     * Thread #1 releases buffer with bdbuf_release_modified() call.
+     */
+    CONTINUE_THREAD(1);
+
+    /*
+     * Step 5:
+     * On buffer release operation, we should have unblock
+     * of thread #2 that is waiting on read buffer operation.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("5");
+
+   /*
+    * Step 6:
+    * Wait swapout period and check that there is no
+    * request to flush buffer onto a disk.
+    */
+    CHECK_NO_DRV_MSG();
+
+    /*
+     * Step 7:
+     * Thread #2 releases buffer with bdbuf_release_modified() call.
+     */
+    CONTINUE_THREAD(2);
+
+    /*
+     * Step 8:
+     * Check that in swapout interval disk device
+     * driver is requested to flush buffer.
+     */
+    WAIT_DRV_MSG_WR(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test2_2_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1 - 3:
+     * Try to read blk #N on thread #1
+     * We will block on this read and meanwhile
+     * thread #2 will try to read the same block.
+     * After blocking on read in thread #2, device
+     * driver will notify successful completion of 
+     * date transfer, and as the result this call 
+     * will return valid buffer.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(1);
+
+    /*
+     * Step 4:
+     * Release buffer returned on the previous step.
+     */
+    rc = rtems_bdbuf_release_modified(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test2_2_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * Try to read block #N. Right now thread #1 is waiting
+     * on data transfer operation, so we will block here as well.
+     *
+     * Step 5:
+     * On step 4 thread #1 releases buffer and as the result 
+     * our read operation should finish with success. 
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    CONTINUE_MAIN(2);
+
+    /*
+     * Step 7:
+     * Release buffer.
+     */
+    rc = rtems_bdbuf_release_modified(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+
Index: testsuites/libtests/block08/bdbuf_test3_1.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test3_1.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test3_1.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,184 @@
+/*! @file
+ * @brief Check how read/release work in case of only one buffer in ready list.
+ *
+ * Test sequence:
+ * -# In thread #1 call rtems_bdbuf_get(#N) to get an empty block #N.
+ * -# In thread #1 call rtems_bdbuf_release_modified() for previously 
+ *    got buffer.
+ * -# In thread #1 call rtems_bdbuf_read(#N) to get the same buffer
+ *    (after this call a buffer is in AVL tree with ACCESS_MODIFIED state).
+ * -# In thread #2 call rtems_bdbuf_read/get(#M).
+ * -# In thread #1 call rtems_bdbuf_release(#N).
+ * -# Check that in thread #2 a buffer is obtained.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test3_1_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test3_1_thread2(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM_N 80
+#define TEST_BLK_NUM_M 85
+
+void
+bdbuf_test3_1_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 3.1");
+
+    START_THREAD(1, bdbuf_test3_1_thread1);
+    START_THREAD(2, bdbuf_test3_1_thread2);
+
+    /*
+     * Step 1-3:
+     * Wait for sync from thread #1.
+     * Thread #1 switch a buffer for #N into ACCESS_MODIFIED state.
+     */
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("3");
+
+    /*
+     * Step 4:
+     * Thread #2 calls get() function and blocks
+     * (there no buffers available in bdbuf library).
+     */
+    CONTINUE_THREAD(2);
+
+    /* Make sure thread #2 managed to block on the buffer. */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 6:
+     * Thread #1 release buffer.
+     */
+    CONTINUE_THREAD(1);
+
+    /*
+     * Buffer released in thread #1 was in MODIFIED state, so
+     * there will be a request for disk write
+     */
+    WAIT_DRV_MSG_WR(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Check that thread #2 unblocked after this.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("5");
+
+    /* 
+     * Release buffer in thread #2
+     */
+    CONTINUE_THREAD(2);
+
+    /*
+     * Buffer released in thread #2 switched to MODIFIED state, so
+     * there will be a request for disk write
+     */
+    WAIT_DRV_MSG_WR(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test3_1_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_get(#N) to get an empty block db;
+     * [this call will remove a buffer from ready list and insert
+     * it in AVL tree with ACCESS state.
+     * Step 2:
+     * Call release_modified(bd);
+     * [Now we have one entry in modified list and it is still 
+     * in AVL tree with MODIFIED state]
+     * Step 3: 
+     * Call read(#N) to get the same buffer.
+     * [An entry is found in AVL tree, removed from modified list and 
+     * returned with state ACCESS_MODIFIED]
+     */
+    rc = rtems_bdbuf_get(test_dev, TEST_BLK_NUM_N, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    
+    rc = rtems_bdbuf_release_modified(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    /* Step 5:
+     * Call rtems_bdbuf_release(#N).
+     * As the result buffer will be used by bdbuf to get 
+     * buffer #M for thread #2.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test3_1_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 4:
+     * In thread #2 call read/get(#M)
+     * [We ask for block number #M - there is no such entry in AVL,
+     * and all the lists are empty (ready, lru, modified), as a result
+     * this thread blocks on 
+     * rtems_bdbuf_wait(pool, &pool->waiting, &pool->wait_waiters)]
+     */
+    rc = rtems_bdbuf_get(test_dev, TEST_BLK_NUM_M, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(2);
+
+    /*
+     * Release buffer.
+     */
+    rc = rtems_bdbuf_release_modified(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+
Index: testsuites/libtests/block08/bdbuf_test3_2.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test3_2.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test3_2.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,197 @@
+/*! @file
+ * @brief Check that when there are some tasks waiting for an available
+ * buffer only one of them get a buffer after some other task releases one.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read(#N1) in thread #1.
+ * -# Call rtems_bdbuf_get(#N2) in thread #2.
+ *    This thread blocks because we have no buffers available.
+ * -# Call rtems_bdbuf_get(#N3) in thread #3.
+ *    This thread also blocks because we have no buffers available.
+ * -# Call rtems_bdbuf_release_modified(#N1) in thread #1.
+ * -# Check that only one thread (thread #2 or thread #3) got a buffer.
+ *     Another thread shall still be blocked.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test3_2_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test3_2_thread2(rtems_task_argument arg);
+static rtems_task bdbuf_test3_2_thread3(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM_N1 90
+#define TEST_BLK_NUM_N2 92
+#define TEST_BLK_NUM_N3 94
+
+void
+bdbuf_test3_2_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 3.2");
+
+    /*
+     * Create working threads.
+     */
+    SET_THREAD_PRIORITY(2, LOW);
+    SET_THREAD_PRIORITY(3, HIGH);
+    START_THREAD(1, bdbuf_test3_2_thread1);
+    START_THREAD(2, bdbuf_test3_2_thread2);
+    START_THREAD(3, bdbuf_test3_2_thread3);
+
+    /*
+     * Start thread #1: it will read buffer #N1.
+     * Driver is asked to read this buffer.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    WAIT_THREAD_SYNC(1);
+
+    /*
+     * Block thread #2 and thread #3 on get buffers #N1 and #N2
+     * correspondingly.
+     */
+    CONTINUE_THREAD(2);
+    CONTINUE_THREAD(3);
+
+    /* Make sure threads managed to block on the buffers get. */
+    CHECK_THREAD_BLOCKED(2);
+    CHECK_THREAD_BLOCKED(3);
+
+    /*
+     * Step 4:
+     * Thread #1 release buffer.
+     */
+    CONTINUE_THREAD(1);
+
+    /*
+     * Check that thread #2 unblocked after this.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("5");
+
+    CHECK_THREAD_BLOCKED(3);
+
+    /* Release buffer in thread #2 */
+    CONTINUE_THREAD(2);
+
+    /* wait for driver message to flush it onto a disk */
+    WAIT_DRV_MSG_WR(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /* Wait for thread #3 to be unblocked */
+    WAIT_THREAD_SYNC(3);
+
+    /* Release buffer in thread #3 */
+    CONTINUE_THREAD(3);
+
+    /* wait for driver message to flush it onto a disk */
+    WAIT_DRV_MSG_WR(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test3_2_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_read(#N) to get a buffer;
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N1, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    /*
+     * Step 4:
+     * Call rtems_bdbuf_release(#N).
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test3_2_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * In thread #2 call get(#N2)
+     */
+    rc = rtems_bdbuf_get(test_dev, TEST_BLK_NUM_N2, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    printk("Thread #2 DEBLOCK\n");
+    CONTINUE_MAIN(2);
+
+    rc = rtems_bdbuf_release_modified(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test3_2_thread3(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(3);
+
+    /*
+     * Step 3:
+     * In thread #3 call get(#N3)
+     */
+    rc = rtems_bdbuf_get(test_dev, TEST_BLK_NUM_N3, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    printk("Thread #3 DEBLOCK\n");
+
+    CONTINUE_MAIN(3);
+    
+    rc = rtems_bdbuf_release_modified(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    THREAD_END();
+}
+
Index: testsuites/libtests/block08/bdbuf_test3_3.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test3_3.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test3_3.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,208 @@
+/*! @file
+ * @brief Check how read/release work in case of only one buffer in ready list.
+ *
+ * The same as Test 3.2, but instead of calling rtems_bdbuf_get() in 
+ * threads #1 and #2, it calls rtems_bdbuf_read().
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read(#N1) in thread #1.
+ * -# Call rtems_bdbuf_read(#N2) in thread #2.
+ *    This thread blocks because we have no buffers available.
+ * -# Call rtems_bdbuf_read(#N3) in thread #3.
+ *    This thread also blocks because we have no buffers available.
+ * -# Call rtems_bdbuf_release(#N1) in thread #1.
+ * -# Check that only one thread (thread #2 or thread #3) got a buffer.
+ *    Another thread shall still be blocked.
+ * -# Call rtems_bdbuf_release(#N2) in thread #2 and check that 
+ *    thread #3 got a buffer as the result.
+ * .
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test3_3_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test3_3_thread2(rtems_task_argument arg);
+static rtems_task bdbuf_test3_3_thread3(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM_N1 96
+#define TEST_BLK_NUM_N2 98
+#define TEST_BLK_NUM_N3 100
+
+void
+bdbuf_test3_3_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 3.3");
+
+    /*
+     * Create working threads.
+     */
+    SET_THREAD_PRIORITY(2, LOW);
+    SET_THREAD_PRIORITY(3, HIGH);
+    START_THREAD(1, bdbuf_test3_3_thread1);
+    START_THREAD(2, bdbuf_test3_3_thread2);
+    START_THREAD(3, bdbuf_test3_3_thread3);
+
+    /*
+     * Start thread #1: it will read buffer #N1.
+     * Driver is asked to read this buffer.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    WAIT_THREAD_SYNC(1);
+
+    /*
+     * Block thread #2 and thread #3 on get buffers #N2 and #N3
+     * correspondingly (bdbuf librbary has no buffers available).
+     */
+    CONTINUE_THREAD(2);
+    CONTINUE_THREAD(3);
+
+    /* Make sure threads managed to block on the buffers get. */
+    CHECK_THREAD_BLOCKED(2);
+    CHECK_THREAD_BLOCKED(3);
+
+    /*
+     * Step 4:
+     * Thread #1 release buffer.
+     */
+    CONTINUE_THREAD(1);
+
+    /* Wait for read request in the driver (for thread #2) */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /* Check that there is no read request for another block */
+    CHECK_NO_DRV_MSG();
+
+    /*
+     * Check that thread #2 unblocked after this.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("5");
+
+    /* Thread #3 is still in blocked state */
+    CHECK_THREAD_BLOCKED(3);
+
+    /* Release buffer in thread #2 */
+    CONTINUE_THREAD(2);
+
+    /* Wait for read request in the driver (for thread #3) */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /* Wait for thread #3 to be unblocked */
+    WAIT_THREAD_SYNC(3);
+
+    /* Release buffer in thread #3 */
+    CONTINUE_THREAD(3);
+
+    CHECK_NO_DRV_MSG();
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test3_3_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_read(#N) to get a buffer;
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N1, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    /*
+     * Step 4:
+     * Call rtems_bdbuf_release(#N).
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test3_3_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * In thread #2 call read(#N2)
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N2, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    printk("Thread #2 DEBLOCK\n");
+    CONTINUE_MAIN(2);
+
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test3_3_thread3(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(3);
+
+    /*
+     * Step 3:
+     * In thread #3 call read(#N3)
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N3, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    printk("Thread #3 DEBLOCK\n");
+
+    CONTINUE_MAIN(3);
+    
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    THREAD_END();
+}
+
Index: testsuites/libtests/block08/bdbuf_test4_1.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test4_1.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test4_1.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,176 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_sync() works.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read(#N) in thread #1.
+ * -# Call rtems_bdbuf_read(#N) from thread #2.
+ * -# Thread #2 blocks on this call.
+ * -# Call rtems_bdbuf_sync(#N) in thread #1.
+ * -# After a while disk driver gets write request for block #N.
+ *    Notify bdbuf library about write complete event.
+ * -# Check that thread #1 unlocked after this.
+ * -# Check that thread #2 unblocks and get buffer #N.
+ * -# Release buffer in thread #2.
+ * .
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test4_1_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test4_1_thread2(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM_N 112
+
+void
+bdbuf_test4_1_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 4.1");
+
+    START_THREAD(1, bdbuf_test4_1_thread1);
+    START_THREAD(2, bdbuf_test4_1_thread2);
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_read(#N) in thread #1.
+     * Wait for read request in disk driver.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /* Wait for return from rtems_bdbuf_read(#N) function. */
+    WAIT_THREAD_SYNC(1);
+
+    /*
+     * Step 2:
+     * Call rtems_bdbuf_read(#N) in thread #2.
+     */
+    CONTINUE_THREAD(2);
+    
+    /* Make sure that thread #2 blocks */
+    CHECK_THREAD_BLOCKED(2);
+    TEST_CHECK_RESULT("2");
+
+    /*
+     * Step 3:
+     * Call rtems_bdbuf_sync (#N) in thread #1.
+     */
+    CONTINUE_THREAD(1);
+
+    /* 
+     * Setp 4:
+     * Wait for Write request to device driver.
+     */
+    WAIT_DRV_MSG_WR(&msg);
+
+    /* Check that both threads are blocked right now */
+    CHECK_THREAD_BLOCKED(1);
+    CHECK_THREAD_BLOCKED(2);
+
+    /* Send Write complete notification */
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Step 5:
+     * Check that rtems_bdbuf_sync(#N) call is unlocked.
+     */
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("5");
+
+    /*
+     * Step 6:
+     * Check that rtems_bdbuf_read(#N) call in thread #2 is unlocked.
+     */
+    WAIT_THREAD_SYNC(2);
+
+    /*
+     * Step 7:
+     * Release buffer in thread #2
+     */
+    CONTINUE_THREAD(2);
+
+    /*
+     * Exit from thread #1.
+     */
+    CONTINUE_THREAD(1);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test4_1_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_read(#N) in thread #1;
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+    
+    /*
+     * Step 3:
+     * Call rtems_bdbuf_sync(#N)
+     */
+    rc = rtems_bdbuf_sync(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test4_1_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 2:
+     * In thread #2 call rtems_bdbuf_read(#N).
+     * We will block on this call.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(2);
+
+    /*
+     * Release buffer.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+
Index: testsuites/libtests/block08/bdbuf_test4_2.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test4_2.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test4_2.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,161 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_sync() works.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read(#N) in thread #1.
+ * -# Call rtems_bdbuf_sync(#N) in thread #1.
+ * -# After a while disk driver gets write request for block #N.
+ * -# Call rtems_bdbuf_read(#N) from thread #2 (before reply from the driver).
+ *    Thread #2 blocks on this call.
+ * -# Notify bdbuf library about write complete event.
+ * -# Check that rtems_bdbuf_sync(#N) in thread #1 unlocked after this.
+ *    (in fact a thread to unlock might be any).
+ * -# Check that thread #2 unblocks and get buffer #N.
+ * -# Release buffer in thread #2.
+ * .
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test4_2_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test4_2_thread2(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM_N 114
+
+void
+bdbuf_test4_2_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 4.2");
+
+    START_THREAD(1, bdbuf_test4_2_thread1);
+    START_THREAD(2, bdbuf_test4_2_thread2);
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_read(#N) in thread #1.
+     * Wait for read request in disk driver.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Step 2, 3:
+     * Call rtems_bdbuf_sync(#N) in thread #1.
+     * As the result buffer is asked to be flashed onto the disk.
+     */
+    WAIT_DRV_MSG_WR(&msg);
+    TEST_CHECK_RESULT("3");
+
+    /*
+     * Step 4:
+     * Call rtems_bdbuf_read(#N) in thread #2
+     */
+    CONTINUE_THREAD(2);
+
+    /* Make sure that thread #2 blocks */
+    CHECK_THREAD_BLOCKED(2);
+
+    /*
+     * Step 5:
+     * Notify bdbuf library about write complete event.
+     */
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /* Check that rtems_bdbuf_sync() is unlocked in thread #1 */
+    WAIT_THREAD_SYNC(1);
+
+    /*
+     * Step 7:
+     * Check that rtems_bdbuf_read(#N) call is unlocked in thread #2.
+     */
+    WAIT_THREAD_SYNC(2);
+    TEST_CHECK_RESULT("7");
+
+    /*
+     * Step 8:
+     * Release buffer in thread #2
+     */
+    CONTINUE_THREAD(2);
+
+    /* Exit from thread #1 */
+    CONTINUE_THREAD(1);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test4_2_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_read(#N) in thread #1;
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    /*
+     * Step 2:
+     * Call rtems_bdbuf_sync(#N)
+     */
+    rc = rtems_bdbuf_sync(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test4_2_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 4:
+     * In thread #2 call read(#N).
+     * We will block on this call.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(2);
+
+    /*
+     * Release buffer.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+
Index: testsuites/libtests/block08/bdbuf_test4_3.c
===================================================================
--- testsuites/libtests/block08/bdbuf_test4_3.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_test4_3.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,155 @@
+/*! @file
+ * @brief Check how rtems_bdbuf_sync() works.
+ *
+ * Test sequence:
+ * -# Call rtems_bdbuf_read(#N) in thread #1.
+ * -# Call rtems_bdbuf_sync(#N) in thread #1.
+ * -# After a while disk driver gets write request for block #N.
+ *    Notify bdbuf about write complete event.
+ * -# Check that rtems_bdbuf_sync(#N) in thread #1 unlocked after this.
+ * -# Call rtems_bdbuf_read(#N) in thread #2.
+ * -# Check that buffer is successfully obtained in thread #2.
+ * -# Call rtems_bdbuf_release(#N) in thread #2.
+ * .
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <bdbuf_tests.h>
+
+static rtems_task bdbuf_test4_3_thread1(rtems_task_argument arg);
+static rtems_task bdbuf_test4_3_thread2(rtems_task_argument arg);
+
+/* Block number used in the test */
+#define TEST_BLK_NUM_N 116
+
+void
+bdbuf_test4_3_main()
+{
+    bdbuf_test_msg msg;
+
+    TEST_START("Test 4.3");
+
+    START_THREAD(1, bdbuf_test4_3_thread1);
+    START_THREAD(2, bdbuf_test4_3_thread2);
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_read(#N) in thread #1.
+     * Wait for read request in disk driver.
+     */
+    WAIT_DRV_MSG(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Step 2:
+     * Call rtems_bdbuf_sync(#N) in thread #1.
+     * As the result buffer is asked to be flashed onto the disk.
+     */
+    WAIT_DRV_MSG_WR(&msg);
+    SEND_DRV_MSG(0, 0, RTEMS_SUCCESSFUL, 0);
+
+    /*
+     * Step 4:
+     * Check that rtems_bdbuf_sync(#N) call is unlocked.
+     */
+    WAIT_THREAD_SYNC(1);
+    TEST_CHECK_RESULT("4");
+
+    /*
+     * Step 5:
+     * Call rtems_bdbuf_read(#N) in thread #2.
+     */
+    CONTINUE_THREAD(2);
+
+    /*
+     * Step 6:
+     * Check that thread #2 successfully got the buffer.
+     */
+    WAIT_THREAD_SYNC(2);
+
+    /*
+     * Step 7:
+     * Release buffer in thread #2
+     */
+    CONTINUE_THREAD(2);
+
+    /*
+     * Exit from thread #1.
+     */
+    CONTINUE_THREAD(1);
+
+    TEST_END();
+}
+
+static rtems_task
+bdbuf_test4_3_thread1(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    /*
+     * Step 1:
+     * Call rtems_bdbuf_read(#N) in thread #1;
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    /*
+     * Step 2:
+     * Call rtems_bdbuf_sync(#N)
+     */
+    rc = rtems_bdbuf_sync(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(1);
+
+    THREAD_END();
+}
+
+static rtems_task
+bdbuf_test4_3_thread2(rtems_task_argument arg)
+{
+    rtems_status_code   rc;
+    rtems_bdbuf_buffer *bd = NULL;
+
+    WAIT_MAIN_SYNC(2);
+
+    /*
+     * Step 5:
+     * In thread #2 call rtems_bdbuf_read(#N).
+     * We will block on this call.
+     */
+    rc = rtems_bdbuf_read(test_dev, TEST_BLK_NUM_N, &bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+
+    CONTINUE_MAIN(2);
+
+    /*
+     * Release buffer.
+     */
+    rc = rtems_bdbuf_release(bd);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        TEST_FAILED();
+    }
+    THREAD_END();
+}
+
+
Index: testsuites/libtests/block08/bdbuf_tests.c
===================================================================
--- testsuites/libtests/block08/bdbuf_tests.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_tests.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,271 @@
+/*! @file
+ * @brief Implementation of auxiliary functions of bdbuf tests.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/io.h>
+#include <rtems/diskdevs.h>
+#include <rtems/bdbuf.h>
+#include "bdbuf_tests.h"
+
+
+struct bdbuf_test_descr {
+    void (* main)(void);
+} bdbuf_tests[] = {
+#if 0
+    { bdbuf_test1_1_main },
+    { bdbuf_test1_2_main },
+    { bdbuf_test1_3_main },
+#endif
+    { bdbuf_test1_4_main },
+    { bdbuf_test1_5_main },
+    
+    { bdbuf_test2_1_main },
+    { bdbuf_test2_2_main },
+    
+    { bdbuf_test3_1_main },
+    { bdbuf_test3_2_main },
+    { bdbuf_test3_3_main },
+    
+    { bdbuf_test4_1_main },
+    { bdbuf_test4_2_main },
+    { bdbuf_test4_3_main },
+};
+
+#define TEST_SEM_ATTRIBS RTEMS_DEFAULT_ATTRIBUTES
+
+/** Device ID used for testing */
+dev_t      test_dev = (dev_t)-1;
+
+/** Test result variable */
+bool       good_test_result = true;
+
+test_ctx g_test_ctx;
+
+const char *test_name = "NO TEST";
+
+bdbuf_test_msg test_drv_msg;
+
+/** Count of messages in RX message queue used on disk driver side. */
+#define TEST_DRV_RX_MQUEUE_COUNT 10
+/** Name of disk driver RX message queue. */
+#define TEST_DRV_RX_MQUEUE_NAME  (rtems_build_name( 'M', 'Q', 'D', ' ' ))
+
+/** Count of messages in Test task RX message queue */
+#define TEST_TASK_RX_MQUEUE_COUNT 10
+/** Name of Test task RX message queue */
+#define TEST_TASK_RX_MQUEUE_NAME  (rtems_build_name( 'M', 'Q', 'T', ' ' ))
+
+rtems_status_code
+bdbuf_test_start_aux_task(rtems_name name,
+                          rtems_task_entry entry_point,
+                          rtems_task_argument arg,
+                          Objects_Id *id)
+{
+    rtems_status_code rc;
+    Objects_Id        task_id;
+
+    rc = rtems_task_create(name, BDBUF_TEST_THREAD_PRIO_NORMAL, 1024 * 2,
+                           RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
+                           RTEMS_LOCAL | RTEMS_NO_FLOATING_POINT,
+                           &task_id);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        printf("Failed to create task\n");
+        return rc;
+    }
+    
+    rc = rtems_task_start(task_id, entry_point, arg);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        printf("Failed to start task\n");
+    }
+    else
+    {
+        if (id != NULL)
+            *id = task_id;
+    }
+    return rc;
+}
+
+void
+run_bdbuf_tests()
+{
+    rtems_disk_device  *disk;
+    rtems_status_code   sc;
+    dev_t               dev = -1;
+    unsigned int        i;
+
+    rtems_device_major_number  major;
+    rtems_driver_address_table testdisk = {
+        test_disk_initialize,
+        RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES
+    };
+
+    /* Create a message queue to get events from disk driver. */
+    sc = rtems_message_queue_create(TEST_TASK_RX_MQUEUE_NAME,
+                                    TEST_TASK_RX_MQUEUE_COUNT,
+                                    sizeof(bdbuf_test_msg),
+                                    RTEMS_DEFAULT_ATTRIBUTES,
+                                    &g_test_ctx.test_qid);
+
+    if (sc != RTEMS_SUCCESSFUL)
+    {
+        printk("Failed to create message queue for test task: %u\n", sc);
+        return;
+    }
+
+    /* Register a disk device that is used in tests */
+    sc = rtems_io_register_driver(0, &testdisk, &major);
+    if (sc != RTEMS_SUCCESSFUL)
+    {
+        printk("Failed to register TEST DEVICE: %d\n", sc);
+        return;
+    }
+
+    test_dev = -1;
+    while ((disk = rtems_disk_next(dev)) != NULL)
+    {
+        printk("DEV: %s [%lu]\n", disk->name, disk->size);
+        dev = disk->dev;
+        if (strcmp(disk->name, TEST_DISK_NAME) == 0)
+            test_dev = dev;
+        rtems_disk_release(disk);
+    }
+
+    if (test_dev == (dev_t)-1)
+    {
+        printf("Failed to find %s disk\n", TEST_DISK_NAME);
+        return;
+    }
+
+    /*
+     * On initialization test disk device driver registers
+     * its RX message queue, so we just need to locate it.
+     */
+    sc = rtems_message_queue_ident(TEST_DRV_RX_MQUEUE_NAME,
+                                   RTEMS_SEARCH_ALL_NODES,
+                                   &g_test_ctx.test_drv_qid);
+    if (sc != RTEMS_SUCCESSFUL)
+    {
+        printf("Failed to find Test Driver Queue: %u\n", sc);
+        return;
+    }
+
+    for (i = 0; i < ARRAY_NUM(g_test_ctx.test_sync_main); i++)
+    {
+        sc = rtems_semaphore_create(rtems_build_name('T', 'S', 'M', '0' + i),
+                                    0, TEST_SEM_ATTRIBS, 0,
+                                    &g_test_ctx.test_sync_main[i]);
+        if (sc != RTEMS_SUCCESSFUL)
+        {
+            printk("Failed to create sync sem for test task: %u\n", sc);
+            return;
+        }
+    }
+
+    for (i = 0; i < ARRAY_NUM(g_test_ctx.test_sync); i++)
+    {
+        sc = rtems_semaphore_create(rtems_build_name('T', 'S', 'T', '0' + i),
+                                    0, TEST_SEM_ATTRIBS, 0,
+                                    &g_test_ctx.test_sync[i]);
+        if (sc != RTEMS_SUCCESSFUL)
+        {
+            printk("Failed to create sync sem for test task #%d: %u\n", i + 1, sc);
+            return;
+        }
+    }
+    
+    sc = rtems_semaphore_create(rtems_build_name('T', 'S', 'M', 'E'),
+                                0, TEST_SEM_ATTRIBS, 0,
+                                &g_test_ctx.test_end_main);
+    if (sc != RTEMS_SUCCESSFUL)
+    {
+        printk("Failed to create end sync sem for test task: %u\n", sc);
+        return;
+    }
+
+    for (i = 0; i < ARRAY_NUM(g_test_ctx.test_task); i++)
+        g_test_ctx.test_task[i] = OBJECTS_ID_NONE;
+
+    for (i = 0; i < sizeof(bdbuf_tests) / sizeof(bdbuf_tests[0]); i++)
+    {
+        bdbuf_tests[i].main();
+    }
+}
+
+
+rtems_status_code
+bdbuf_test_create_drv_rx_queue(Objects_Id *id)
+{
+    return rtems_message_queue_create(TEST_DRV_RX_MQUEUE_NAME,
+                                      TEST_DRV_RX_MQUEUE_COUNT,
+                                      sizeof(bdbuf_test_msg),
+                                      RTEMS_DEFAULT_ATTRIBUTES,
+                                      id);
+}
+
+rtems_status_code
+bdbuf_test_create_drv_tx_queue(Objects_Id *id)
+{
+    return  rtems_message_queue_ident(TEST_TASK_RX_MQUEUE_NAME,
+                                      RTEMS_SEARCH_ALL_NODES,
+                                      id);
+}
+
+rtems_status_code
+bdbuf_test_start_thread(unsigned int idx, rtems_task_entry func)
+{
+    rtems_status_code sc;
+
+    if (g_test_ctx.test_task[idx] != OBJECTS_ID_NONE)
+    {
+        sc = rtems_task_delete(g_test_ctx.test_task[idx]);
+        if (sc != RTEMS_SUCCESSFUL)
+        {
+            printk("Failed to delete test thread %u in test %s\n",
+                   idx + 1, g_test_ctx.test_name);
+            return sc;
+        }
+    }
+    sc = bdbuf_test_start_aux_task(
+            rtems_build_name('T', 'S', '.', '0' + idx),
+            func, (rtems_task_argument)(NULL),
+            &g_test_ctx.test_task[idx]);
+    return sc;
+}
+
+rtems_status_code
+bdbuf_test_end()
+{
+    rtems_status_code sc;
+    unsigned int      i;
+
+    for (i = 0; i < ARRAY_NUM(g_test_ctx.test_task); i++)
+    {
+        if (g_test_ctx.test_task[i] != OBJECTS_ID_NONE)
+        {
+            sc = rtems_semaphore_obtain(g_test_ctx.test_end_main,
+                                        RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+            if (sc != RTEMS_SUCCESSFUL)
+            {
+                printk("Failed to get a thread stopped\n");
+            }
+            g_test_ctx.test_task[i] = OBJECTS_ID_NONE;
+        }
+    }
+    return RTEMS_SUCCESSFUL;
+}
+
Index: testsuites/libtests/block08/bdbuf_tests.h
===================================================================
--- testsuites/libtests/block08/bdbuf_tests.h	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/bdbuf_tests.h	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,504 @@
+/*! @file
+ * @brief Common declarations of bdbuf tests.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#ifndef BDBUF_TESTS_H
+#define BDBUF_TESTS_H
+
+#include <stdio.h>
+#include <errno.h>
+#include <rtems/diskdevs.h>
+#include <rtems/bdbuf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void run_bdbuf_tests(void);
+
+extern void bdbuf_test1_1_main(void);
+extern void bdbuf_test1_2_main(void);
+extern void bdbuf_test1_3_main(void);
+extern void bdbuf_test1_4_main(void);
+extern void bdbuf_test1_5_main(void);
+
+extern void bdbuf_test2_1_main(void);
+extern void bdbuf_test2_2_main(void);
+extern void bdbuf_test2_3_main(void);
+extern void bdbuf_test2_4_main(void);
+extern void bdbuf_test2_5_main(void);
+
+extern void bdbuf_test3_1_main(void);
+extern void bdbuf_test3_2_main(void);
+extern void bdbuf_test3_3_main(void);
+
+extern void bdbuf_test4_1_main(void);
+extern void bdbuf_test4_2_main(void);
+extern void bdbuf_test4_3_main(void);
+
+extern rtems_device_driver
+test_disk_initialize(
+    rtems_device_major_number major,
+    rtems_device_minor_number minor,
+    void *arg);
+
+#define ARRAY_NUM(a_) (sizeof(a_) / sizeof(a_[0]))
+
+/**
+ * Configuration parameters of Test disk device.
+ */
+#define TEST_DISK_BLOCK_SIZE   512
+#define TEST_DISK_BLOCK_NUM    1024
+#define TEST_DISK_NAME         "/dev/testdisk"
+
+/** Type of messages between test disk driver and main test task */
+enum bdbuf_test_msg_type {
+    /** Message sent by disk driver to main test task */
+    BDBUF_TEST_MSG_TYPE_DRIVER_REQ,
+    /**
+     * Message sent main test task to disk driver
+     * in reply to request.
+     */
+    BDBUF_TEST_MSG_TYPE_DRIVER_REPLY,
+};
+
+/**
+ * Message used in communication between test disk driver
+ * and main test task.
+ * All R/W requests obtained by driver (from bdbuf library)
+ * are directed to main test task. Then main test task 
+ * sends a reply after which test disk driver notifies 
+ * bdbuf library about operation complete event.
+ */
+typedef struct bdbuf_test_msg {
+    /** Message type */
+    enum bdbuf_test_msg_type type;
+
+    union {
+        struct driver_req {
+            dev_t     dev;
+            uint32_t  req;
+            void     *argp;
+        } driver_req;
+        struct driver_reply {
+            int               ret_val;
+            int               ret_errno;
+            rtems_status_code res_status;
+            int               res_errno;
+        } driver_reply;
+    } val;
+} bdbuf_test_msg;
+
+
+typedef enum bdbuf_rest_thread_prio {
+    BDBUF_TEST_THREAD_PRIO_NORMAL = 3,
+    BDBUF_TEST_THREAD_PRIO_LOW = 7,
+    BDBUF_TEST_THREAD_PRIO_HIGH = 5,
+} bdbuf_rest_thread_prio;
+
+
+typedef struct test_ctx {
+    /**
+     * Message queue used by main task to get messages from
+     * disk device driver.
+     */
+    Objects_Id test_qid;
+   
+    /**
+     * Object ID for disk driver queue.
+     * Test task will send messages to this queue in reply
+     * to messages received on @a test_qid.
+     */
+    Objects_Id test_drv_qid;
+
+    /** Test name */
+    const char *test_name;
+
+    /** 
+     * Semaphore used for synchronization between test thread
+     * and main test task.
+     * Main test task blocks on one of these semaphores and an auxiliary thread
+     * releases it in order to pass control to main task again.
+     */
+    rtems_id   test_sync_main[3];
+
+    /**
+     * This semaphore is used for synchornization between main test task
+     * and the END of auxiliary threads.
+     */
+    rtems_id   test_end_main;
+
+    /**
+     * Semaphore used for synchronization between test thread
+     * and main test task.
+     * Thread #N blocks on this semaphore and the main task releases it
+     * when it wants to pass control to the auxiliary thread #N.
+     */
+    rtems_id   test_sync[3];
+
+    /** Task Id values of auxiliary threads */
+    Objects_Id test_task[3];
+} test_ctx;
+
+extern test_ctx g_test_ctx;
+
+/** Device ID used for testing */
+extern dev_t      test_dev;
+
+/**
+ * Create a message queue for test driver that is used for
+ * receiving messages from test task.
+ *
+ * @param[out] id  RTEMS message queue identifier
+ *
+ * @return Status of the operation
+ */
+extern rtems_status_code bdbuf_test_create_drv_rx_queue(Objects_Id *id);
+
+/**
+ * Obtain a message queue for test driver that is used for
+ * sending messages to test task.
+ *
+ * @param[out] id  RTEMS message queue identifier
+ *
+ * @return Status of the operation
+ */
+extern rtems_status_code bdbuf_test_create_drv_tx_queue(Objects_Id *id);
+
+/**
+ * Start a separate test task represented by function @p func
+ * and associated with task index @p idx.
+ *
+ * @param[in] idx   Task index
+ * @param[in] func  Test task function
+ */
+extern rtems_status_code bdbuf_test_start_thread(unsigned int idx,
+                                                 rtems_task_entry func);
+
+/**
+ * Finalize test run.
+ */
+extern rtems_status_code bdbuf_test_end(void);
+
+/** Test result variable */
+extern bool       good_test_result;
+
+#define BDBUF_TEST_BLOCK_TIMEOUT (2 * rtems_clock_get_ticks_per_second())
+
+#define SET_THREAD_PRIORITY(t_num_, prio_) \
+    do {                                                        \
+        rtems_task_priority old_prio;                           \
+        rtems_status_code   rc_;                                \
+                                                                \
+        rc_ = rtems_task_set_priority(                          \
+                g_test_ctx.test_task[(t_num_) - 1],             \
+                BDBUF_TEST_THREAD_PRIO_ ## prio_, &old_prio);   \
+        if (rc_ != RTEMS_SUCCESSFUL)                            \
+        {                                                       \
+            printk("Failed to change priority of test thread #" \
+                   #t_num_ " in test %s\n", g_test_ctx.test_name);         \
+            return;                                             \
+        }                                                       \
+    } while (0)
+
+/**
+ * Start thread number @p t_num_ with @p func_ function 
+ * as an entry point of the thread.
+ *
+ * @param t_num_  thread number.
+ * @param func_   thread entry point.
+ */
+#define START_THREAD(t_num_, func_) \
+    do {                                                        \
+        if (bdbuf_test_start_thread((t_num_) - 1, func_) !=     \
+                RTEMS_SUCCESSFUL)                               \
+        {                                                       \
+            return;                                             \
+        }                                                       \
+        printk("Thread #" #t_num_ " started\n");                \
+    } while (0)
+
+/**
+ * Wait for a message from device driver.
+ *
+ * @param[out] msg_  Pointer to a message data structure
+ */
+#define WAIT_DRV_MSG(msg_) \
+    do {                                                        \
+        rtems_status_code rc_;                                  \
+        size_t            msg_size_ = sizeof(*(msg_));          \
+                                                                \
+        rc_ = rtems_message_queue_receive(g_test_ctx.test_qid,  \
+                                          (msg_), &msg_size_,   \
+                                          RTEMS_WAIT,           \
+                                          RTEMS_NO_TIMEOUT);    \
+        if (rc_ != RTEMS_SUCCESSFUL ||                          \
+            msg_size_ != sizeof(*(msg_)))                       \
+        {                                                       \
+            printk("Error at %s:%d\n", __FILE__, __LINE__);     \
+            return;                                             \
+        }                                                       \
+        if ((msg_)->type != BDBUF_TEST_MSG_TYPE_DRIVER_REQ)     \
+        {                                                       \
+            printk("Unexpected message received: %d\n",         \
+                   (msg_)->type);                               \
+            return;                                             \
+        }                                                       \
+    } while (0)
+
+#define WAIT_DRV_MSG_WR(msg_) \
+    do {                                                                \
+        WAIT_DRV_MSG(msg_);                                             \
+        if ((msg_)->val.driver_req.req != RTEMS_BLKIO_REQUEST ||        \
+            (msg_)->val.driver_req.dev != test_dev ||                   \
+            ((rtems_blkdev_request *)                                   \
+                 ((msg_)->val.driver_req.argp))->req !=                 \
+                 RTEMS_BLKDEV_REQ_WRITE)                                \
+        {                                                               \
+            printk("Unexpected message received by disk driver: "       \
+                   "req - 0x%x (0x%x), dev - %d (%d)\n",                \
+                   (msg_)->val.driver_req.req, RTEMS_BLKIO_REQUEST,     \
+                   (msg_)->val.driver_req.dev, test_dev);               \
+            return;                                                     \
+        }                                                               \
+    } while (0)
+
+#define CHECK_NO_DRV_MSG() \
+    do {                                                        \
+        rtems_status_code rc_;                                  \
+        bdbuf_test_msg    msg_;                                 \
+        size_t            msg_size_ = sizeof(msg_);             \
+                                                                \
+        rc_ = rtems_message_queue_receive(g_test_ctx.test_qid,  \
+                  (&msg_), &msg_size_,                          \
+                  RTEMS_WAIT,                                   \
+                  BDBUF_TEST_BLOCK_TIMEOUT);                    \
+        if (rc_ != RTEMS_TIMEOUT)                               \
+        {                                                       \
+            printk("Error at %s:%d\n", __FILE__, __LINE__);     \
+            return;                                             \
+        }                                                       \
+    } while (0)
+
+extern bdbuf_test_msg test_drv_msg;
+
+/**
+ * Send a message to device driver (in order to complete
+ * blocked I/O operation).
+ *
+ * @param ret_val_     Return value to use when returning from
+ *                     ioctl() function.
+ * @param ret_errno_   errno value to set to errno variable.
+ * @param res_status_  In case return value from the ioctl()
+ *                     function is equal to 0, this value 
+ *                     is used as status code in asynchronous
+ *                     notification.
+ * @param res_errno_   In case return value from the ioctl()
+ *                     function is equal to 0, this value
+ *                     is used as error value in asynchronous
+ *                     notification.
+ *
+ */
+#define SEND_DRV_MSG(ret_val_, ret_errno_, res_status_, res_errno_) \
+    do {                                                                \
+        rtems_status_code rc_;                                          \
+                                                                        \
+        memset(&test_drv_msg, 0, sizeof(test_drv_msg));                 \
+        test_drv_msg.type = BDBUF_TEST_MSG_TYPE_DRIVER_REPLY;           \
+        test_drv_msg.val.driver_reply.ret_val = (ret_val_);             \
+        test_drv_msg.val.driver_reply.ret_errno = (ret_errno_);         \
+        test_drv_msg.val.driver_reply.res_status = (res_status_);       \
+        test_drv_msg.val.driver_reply.res_errno = (res_errno_);         \
+                                                                        \
+        rc_ = rtems_message_queue_send(g_test_ctx.test_drv_qid,         \
+                                       &test_drv_msg,                   \
+                                       sizeof(test_drv_msg));           \
+        if (rc_ != RTEMS_SUCCESSFUL)                                    \
+        {                                                               \
+            printk("Error while sending a message to "                  \
+                   "disk driver: %u\n", rc_);                           \
+            return;                                                     \
+        }                                                               \
+    } while (0)
+
+/**
+ * Block main test task until a thread passes back control
+ * with CONTINUE_MAIN().
+ *
+ * @param t_num_  thread number from which the main thread 
+ *                is waiting for a sync.
+ */
+#define WAIT_THREAD_SYNC(t_num_) \
+    do {                                                                \
+        rtems_status_code rc_;                                          \
+                                                                        \
+        rc_ = rtems_semaphore_obtain(                                   \
+                g_test_ctx.test_sync_main[(t_num_) - 1],                \
+                RTEMS_WAIT, RTEMS_NO_TIMEOUT);                          \
+        if (rc_ != RTEMS_SUCCESSFUL)                                    \
+        {                                                               \
+            printk("Failed to get sync with a thread: %d\n", rc_);      \
+            return;                                                     \
+        }                                                               \
+    } while (0)
+
+/**
+ * Check that a particular thread is blocked.
+ *
+ * @param t_num_  thread number that we want to check for blocking
+ */
+#define CHECK_THREAD_BLOCKED(t_num_) \
+    do {                                                                \
+        rtems_status_code rc_;                                          \
+                                                                        \
+        rc_ = rtems_semaphore_obtain(                                   \
+                g_test_ctx.test_sync_main[(t_num_) - 1],                \
+                RTEMS_WAIT, BDBUF_TEST_BLOCK_TIMEOUT);                  \
+        if (rc_ != RTEMS_TIMEOUT)                                       \
+        {                                                               \
+            printk("Thread %d is not blocked at%s:%d\n",                \
+                   t_num_, __FILE__, __LINE__);                         \
+            return;                                                     \
+        }                                                               \
+    } while (0)
+
+/**
+ * Main test task gives control to the particular thread.
+ *
+ * @param t_num_  thread number to which main test task wants
+ *                to give control.
+ */
+#define CONTINUE_THREAD(t_num_) \
+    do {                                                        \
+        rtems_status_code rc_;                                  \
+                                                                \
+        rc_ = rtems_semaphore_release(                          \
+                g_test_ctx.test_sync[(t_num_) - 1]);            \
+        if (rc_ != RTEMS_SUCCESSFUL)                            \
+        {                                                       \
+            printk("Failed to give control to thread #"         \
+                   #t_num_ ": %d\n", rc_);                      \
+            return;                                             \
+        }                                                       \
+    } while (0)
+
+/**
+ * Passes control back to the main test task from a thread.
+ *
+ * @param t_num_ Current thread number
+ */
+#define CONTINUE_MAIN(t_num_) \
+    do {                                                        \
+        rtems_status_code rc_;                                  \
+                                                                \
+        rc_ = rtems_semaphore_release(                          \
+                g_test_ctx.test_sync_main[(t_num_) - 1]);       \
+        if (rc_ != RTEMS_SUCCESSFUL)                            \
+        {                                                       \
+            printk("Failed to give control to "                 \
+                   "main task: %d", rc_);                       \
+            return;                                             \
+        }                                                       \
+        rc_ = rtems_semaphore_obtain(                           \
+                g_test_ctx.test_sync[(t_num_) - 1],             \
+                RTEMS_WAIT, RTEMS_NO_TIMEOUT);                  \
+        if (rc_ != RTEMS_SUCCESSFUL)                            \
+        {                                                       \
+            printk("Failed to block on thread #"                \
+                   #t_num_ ": %d\n", rc_);                      \
+            return;                                             \
+        }                                                       \
+    } while (0)
+
+#define WAIT_MAIN_SYNC(t_num_) \
+    do {                                                        \
+        rtems_status_code rc_;                                  \
+                                                                \
+        rc_ = rtems_semaphore_obtain(                           \
+                g_test_ctx.test_sync[(t_num_) - 1],             \
+                RTEMS_WAIT, RTEMS_NO_TIMEOUT);                  \
+        if (rc_ != RTEMS_SUCCESSFUL)                            \
+        {                                                       \
+            printk("Failed to block on thread #"                \
+                   #t_num_ ": %d\n", rc_);                      \
+            return;                                             \
+        }                                                       \
+    } while (0)
+
+
+#define TEST_START(test_name_) \
+    do {                                \
+        good_test_result = true;        \
+        g_test_ctx.test_name = test_name_; \
+        printk("%s - STARTED\n",        \
+               g_test_ctx.test_name);              \
+    } while (0)
+
+#define TEST_CHECK_RESULT(step_) \
+    do {                                        \
+        if (!good_test_result)                  \
+        {                                       \
+            printk("TEST FAILED (Step %s)\n",   \
+                   step_);                      \
+            rtems_task_delete(RTEMS_SELF);      \
+        }                                       \
+        else                                    \
+        {                                       \
+            printk("%s: Step %s - OK\n",        \
+                   g_test_ctx.test_name, step_);           \
+        }                                       \
+    } while (0)
+
+#define TEST_END() \
+    do {                                 \
+        bdbuf_test_end();                \
+                                         \
+        if (good_test_result)            \
+            printk("TEST PASSED\n");     \
+        else                             \
+            printk("TEST FAILED (END)"); \
+    } while (0)
+
+#define THREAD_END() \
+    do {                                                        \
+        rtems_status_code rc_;                                  \
+                                                                \
+        rc_ = rtems_semaphore_release(g_test_ctx.test_end_main);\
+        if (rc_ != RTEMS_SUCCESSFUL)                            \
+        {                                                       \
+            printk("Failed to give control to "                 \
+                   "main task: %d", rc_);                       \
+            return;                                             \
+        }                                                       \
+        rtems_task_delete(RTEMS_SELF);                          \
+    } while (0)
+
+#define TEST_FAILED() \
+    do {                                \
+        good_test_result = false;       \
+    } while (0)
+
+#define SLEEP() \
+    rtems_task_wake_after(BDBUF_TEST_BLOCK_TIMEOUT)
+
+
+extern rtems_status_code
+bdbuf_test_start_aux_task(rtems_name name,
+                          rtems_task_entry entry_point,
+                          rtems_task_argument arg,
+                          Objects_Id *id);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BDBUF_TESTS_H */
+
Index: testsuites/libtests/block08/block08.scn
===================================================================
--- testsuites/libtests/block08/block08.scn	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/block08.scn	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,86 @@
+test_disk_ioctl() Unexpected request comes 2
+TEST DISK - OK
+DEV: /dev/testdisk [1024]
+Test 1.4 - STARTED
+Thread #1 started
+Thread #2 started
+DISK_DRV: R [40]
+Test 1.4: Step 3 - OK
+Test 1.4: Step 5 - OK
+TEST PASSED
+Test 1.5 - STARTED
+Thread #1 started
+Thread #2 started
+DISK_DRV: R [50]
+Test 1.5: Step 1 - OK
+Test 1.5: Step 4 - OK
+TEST PASSED
+Test 2.1 - STARTED
+Thread #1 started
+Thread #2 started
+DISK_DRV: R [60]
+Test 2.1: Step 3 - OK
+Test 2.1: Step 5 - OK
+DISK_DRV: W [60]
+TEST PASSED
+Test 2.2 - STARTED
+Thread #1 started
+Thread #2 started
+DISK_DRV: R [70]
+Test 2.2: Step 3 - OK
+Test 2.2: Step 5 - OK
+DISK_DRV: W [70]
+TEST PASSED
+Test 3.1 - STARTED
+Thread #1 started
+Thread #2 started
+Test 3.1: Step 3 - OK
+DISK_DRV: W [80]
+Test 3.1: Step 5 - OK
+DISK_DRV: W [85]
+TEST PASSED
+Test 3.2 - STARTED
+Thread #1 started
+Thread #2 started
+Thread #3 started
+DISK_DRV: R [90]
+Thread #2 DEBLOCK
+Test 3.2: Step 5 - OK
+DISK_DRV: W [92]
+Thread #3 DEBLOCK
+DISK_DRV: W [94]
+TEST PASSED
+Test 3.3 - STARTED
+Thread #1 started
+Thread #2 started
+Thread #3 started
+DISK_DRV: R [96]
+DISK_DRV: R [98]
+Thread #2 DEBLOCK
+Test 3.3: Step 5 - OK
+DISK_DRV: R [100]
+Thread #3 DEBLOCK
+TEST PASSED
+Test 4.1 - STARTED
+Thread #1 started
+Thread #2 started
+DISK_DRV: R [112]
+Test 4.1: Step 2 - OK
+DISK_DRV: W [112]
+Test 4.1: Step 5 - OK
+TEST PASSED
+Test 4.2 - STARTED
+Thread #1 started
+Thread #2 started
+DISK_DRV: R [114]
+DISK_DRV: W [114]
+Test 4.2: Step 3 - OK
+Test 4.2: Step 7 - OK
+TEST PASSED
+Test 4.3 - STARTED
+Thread #1 started
+Thread #2 started
+DISK_DRV: R [116]
+DISK_DRV: W [116]
+Test 4.3: Step 4 - OK
+TEST PASSED
Index: testsuites/libtests/block08/init.c
===================================================================
--- testsuites/libtests/block08/init.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/init.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,32 @@
+/*  Init
+ *
+ *  This routine is the initialization task for this test program.
+ *
+ *  Input parameters:
+ *    argument - task argument
+ *
+ *  Output parameters:  NONE
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ *  $Id$
+ */
+
+#define CONFIGURE_INIT
+#include "system.h"
+
+#include "bdbuf_tests.h"
+
+rtems_task Init(rtems_task_argument argument)
+{
+  rtems_status_code status;
+
+  run_bdbuf_tests();
+  exit(0);
+}
+
Index: testsuites/libtests/block08/system.h
===================================================================
--- testsuites/libtests/block08/system.h	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/system.h	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,56 @@
+/*  system.h
+ *
+ *  This include file contains information that is included in every
+ *  function in the test set.
+ *
+ *  Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ *  Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ *
+ *  $Id$
+ */
+
+#include <rtems.h>
+#include "rtems/blkdev.h"
+
+rtems_task Init(
+  rtems_task_argument argument
+);
+
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+
+#define CONFIGURE_MAXIMUM_TASKS               28
+#define CONFIGURE_MAXIMUM_TIMERS              10
+#define CONFIGURE_MAXIMUM_SEMAPHORES          20
+#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES      10
+#define CONFIGURE_MAXIMUM_PARTITIONS          1
+#define CONFIGURE_MAXIMUM_REGIONS             1
+#define CONFIGURE_MAXIMUM_PERIODS             1
+#define CONFIGURE_MAXIMUM_USER_EXTENSIONS     0
+#define CONFIGURE_TICKS_PER_TIMESLICE       100
+
+#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
+#define CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS 2
+#define CONFIGURE_BDBUF_CACHE_MEMORY_SIZE   (512)
+#define CONFIGURE_BDBUF_BUFFER_MIN_SIZE     (512)
+#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE     (512)
+
+/* 
+ * Define it here in order to be able to register
+ * test driver after RTEMS initialization phase
+ * (on test start-up).
+ */
+#define CONFIGURE_MAXIMUM_DRIVERS 5
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_INIT_TASK_STACK_SIZE      (4 * RTEMS_MINIMUM_STACK_SIZE)
+
+#define CONFIGURE_EXTRA_TASK_STACKS         (13 * RTEMS_MINIMUM_STACK_SIZE)
+
+#include <rtems/confdefs.h>
+
+/* end of include file */
Index: testsuites/libtests/block08/test_disk.c
===================================================================
--- testsuites/libtests/block08/test_disk.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block08/test_disk.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,154 @@
+/*! @file
+ *  @brief Test disk block device implementation.
+ *
+ * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
+ * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "rtems/blkdev.h"
+#include "rtems/diskdevs.h"
+
+#include "bdbuf_tests.h"
+
+static Objects_Id drvq_id = OBJECTS_ID_NONE;
+static Objects_Id testq_id = OBJECTS_ID_NONE;
+
+static int
+test_disk_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
+{
+    dev_t             dev = rtems_disk_get_device_identifier(dd);
+    rtems_status_code rc;
+    bdbuf_test_msg    msg;
+    size_t            msg_size;
+
+    switch (req)
+    {
+        case RTEMS_BLKIO_REQUEST:
+        {
+            rtems_blkdev_request   *r = argp;
+            rtems_blkdev_sg_buffer *sg;
+            unsigned int            i;
+
+            printk("DISK_DRV: %s ",
+                   r->req == RTEMS_BLKDEV_REQ_READ ? "R" :
+                   r->req == RTEMS_BLKDEV_REQ_WRITE ? "W" : "?");
+            for (i = 0, sg = r->bufs; i < r->bufnum; i++, sg++)
+            {
+                printk("[%d] ", sg->block);
+            }
+            printk("\n");
+            break;
+        }
+
+        default:
+            printk("%s() Unexpected request comes %u\n",
+                   __FUNCTION__, req);
+            return -1;
+    }
+
+    memset(&msg, 0, sizeof(msg));
+    msg.type = BDBUF_TEST_MSG_TYPE_DRIVER_REQ;
+    msg.val.driver_req.dev = dev;
+    msg.val.driver_req.req = req;
+    msg.val.driver_req.argp = argp;
+
+    rc = rtems_message_queue_send(testq_id, &msg, sizeof(msg));
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        printf("Error while sending a message to Test task: %u\n", rc);
+        return -1;
+    }
+
+    /* Wait for a reply from the test task */
+    msg_size = sizeof(msg);
+    rc = rtems_message_queue_receive(drvq_id, &msg, &msg_size,
+                                     RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        printf("Error while reading a message from Test task: %u\n", rc);
+        return rc;
+    }
+    if (msg.type != BDBUF_TEST_MSG_TYPE_DRIVER_REPLY)
+    {
+        printf("Unexpected message comes to test disk driver: %d\n",
+               msg.type);
+        return -1;
+    }
+
+    if (msg.val.driver_reply.ret_val != 0)
+    {
+        errno = msg.val.driver_reply.ret_errno;
+    }
+    else
+    {
+        rtems_blkdev_request *r = (rtems_blkdev_request *)argp;
+
+        r->req_done(r->done_arg, msg.val.driver_reply.res_status);
+    }
+
+    return msg.val.driver_reply.ret_val;
+}
+
+rtems_device_driver
+test_disk_initialize(
+    rtems_device_major_number major,
+    rtems_device_minor_number minor,
+    void *arg)
+{
+    rtems_status_code rc;
+    dev_t             dev;
+
+    rc = rtems_disk_io_initialize();
+    if (rc != RTEMS_SUCCESSFUL)
+        return rc;
+
+    dev = rtems_filesystem_make_dev_t(major, minor);
+    rc = rtems_disk_create_phys(dev,
+                                TEST_DISK_BLOCK_SIZE, TEST_DISK_BLOCK_NUM,
+                                test_disk_ioctl,
+                                NULL,
+                                TEST_DISK_NAME);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        printf("Failed to create %s disk\n", TEST_DISK_NAME);
+        return rc;
+    }
+
+    rc = bdbuf_test_create_drv_rx_queue(&drvq_id);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        printk("%s() Failed to create Msg Queue for RX: %u\n",
+               __FUNCTION__, rc);
+        return rc;
+    }
+
+    rc = bdbuf_test_create_drv_tx_queue(&testq_id);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        printf("%s() Failed to get Msg Queue for TX: %u\n",
+               __FUNCTION__, rc);
+        return rc;
+    }
+
+    printk("TEST DISK - OK\n");
+    return RTEMS_SUCCESSFUL;
+}
+
Index: testsuites/libtests/block09/Makefile.am
===================================================================
--- testsuites/libtests/block09/Makefile.am	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block09/Makefile.am	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,27 @@
+##
+## $Id$
+##
+
+MANAGERS = io semaphore event
+
+rtems_tests_PROGRAMS = block09
+block09_SOURCES = init.c
+
+dist_rtems_tests_DATA = block09.scn block09.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+block09_LDADD = $(MANAGERS_NOT_WANTED:%=$(PROJECT_LIB)/no-%.rel)
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(block09_OBJECTS) $(block09_LDADD)
+LINK_LIBS = $(block09_LDLIBS)
+
+block09$(EXEEXT): $(block09_OBJECTS) $(block09_DEPENDENCIES)
+	@rm -f block09$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
Index: testsuites/libtests/block09/block09.scn
===================================================================
--- testsuites/libtests/block09/block09.scn	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block09/block09.scn	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,2 @@
+*** TEST BLOCK 9 ***
+*** END OF TEST BLOCK 9 ***
Index: testsuites/libtests/block09/init.c
===================================================================
--- testsuites/libtests/block09/init.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
+++ testsuites/libtests/block09/init.c	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -0,0 +1,226 @@
+/**
+ * @file
+ *
+ * @ingroup test_bdbuf
+ *
+ * @brief Bdbuf test for disk driver error handling..
+ */
+
+/*
+ * Copyright (c) 2009
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/bdbuf.h>
+#include <rtems/diskdevs.h>
+
+#define ASSERT_SC(sc) assert((sc) == RTEMS_SUCCESSFUL)
+
+#define BLOCK_SIZE sizeof(char)
+
+#define BLOCK_COUNT 4
+
+#define BLOCK_READ_IO_ERROR 0
+#define BLOCK_READ_UNSATISFIED 1
+#define BLOCK_READ_SUCCESSFUL 2
+#define BLOCK_WRITE_IO_ERROR 3
+
+static char disk_data [BLOCK_COUNT];
+
+static const rtems_driver_address_table disk_ops = {
+  .initialization_entry = NULL,
+  RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES
+};
+
+static int disk_ioctl(rtems_disk_device *dd, uint32_t req, void *arg)
+{
+  rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+  if (req == RTEMS_BLKIO_REQUEST) {
+    rtems_blkdev_request *r = arg;
+    uint32_t i = 0;
+
+    for (i = 0; i < r->bufnum; ++i) {
+      rtems_blkdev_sg_buffer *sg = &r->bufs [i];
+      char *buf = sg->buffer;
+
+      if (sg->length != 1) {
+        return -1;
+      }
+
+      switch (r->req) {
+        case RTEMS_BLKDEV_REQ_READ:
+          switch (sg->block) {
+            case BLOCK_READ_IO_ERROR:
+              sc = RTEMS_IO_ERROR;
+              break;
+            case BLOCK_READ_UNSATISFIED:
+              sc = RTEMS_UNSATISFIED;
+              break;
+            case BLOCK_READ_SUCCESSFUL:
+            case BLOCK_WRITE_IO_ERROR:
+              *buf = disk_data [sg->block];
+              break;
+            default:
+              return -1;
+          }
+          break;
+        case RTEMS_BLKDEV_REQ_WRITE:
+          switch (sg->block) {
+            case BLOCK_READ_IO_ERROR:
+            case BLOCK_READ_UNSATISFIED:
+            case BLOCK_READ_SUCCESSFUL:
+              disk_data [sg->block] = *buf;
+              break;
+            case BLOCK_WRITE_IO_ERROR:
+              sc = RTEMS_IO_ERROR;
+              break;
+            default:
+              return -1;
+          }
+          break;
+        default:
+          return -1;
+      }
+    }
+
+    r->req_done(r->done_arg, sc);
+
+    return 0;
+  } else {
+    return rtems_blkdev_ioctl(dd, req, arg);
+  }
+}
+
+rtems_status_code disk_register(
+  uint32_t block_size,
+  rtems_blkdev_bnum block_count,
+  dev_t *dev_ptr
+)
+{
+  rtems_status_code sc = RTEMS_SUCCESSFUL;
+  rtems_device_major_number major = 0;
+  dev_t dev = 0;
+
+  sc = rtems_io_register_driver(0, &disk_ops, &major);
+  ASSERT_SC(sc);
+
+  dev = rtems_filesystem_make_dev_t(major, 0);
+
+  sc = rtems_disk_create_phys(
+    dev,
+    block_size,
+    block_count,
+    disk_ioctl,
+    NULL,
+    NULL
+  );
+  ASSERT_SC(sc);
+
+  *dev_ptr = dev;
+
+  return RTEMS_SUCCESSFUL;
+}
+
+static void check_read(
+  dev_t dev,
+  rtems_blkdev_bnum block,
+  rtems_status_code expected_sc
+)
+{
+  rtems_status_code sc = RTEMS_SUCCESSFUL;
+  rtems_bdbuf_buffer *bd = NULL;
+
+  sc = rtems_bdbuf_read(dev, block, &bd);
+  assert(sc == expected_sc);
+
+  if (sc == RTEMS_SUCCESSFUL) {
+    sc = rtems_bdbuf_release(bd);
+    ASSERT_SC(sc);
+  }
+}
+
+static rtems_task Init(rtems_task_argument argument)
+{
+  rtems_status_code sc = RTEMS_SUCCESSFUL;
+  rtems_bdbuf_buffer *bd = NULL;
+  dev_t dev = 0;
+
+  printk("\n\n*** TEST BLOCK 9 ***\n");
+
+  sc = rtems_disk_io_initialize();
+  ASSERT_SC(sc);
+
+  sc = disk_register(BLOCK_SIZE, BLOCK_COUNT, &dev);
+  ASSERT_SC(sc);
+
+  check_read(dev, BLOCK_READ_IO_ERROR, RTEMS_IO_ERROR);
+  check_read(dev, BLOCK_READ_UNSATISFIED, RTEMS_UNSATISFIED);
+  check_read(dev, BLOCK_READ_SUCCESSFUL, RTEMS_SUCCESSFUL);
+  check_read(dev, BLOCK_WRITE_IO_ERROR, RTEMS_SUCCESSFUL);
+
+  /* Check write IO error */
+
+  sc = rtems_bdbuf_read(dev, BLOCK_WRITE_IO_ERROR, &bd);
+  ASSERT_SC(sc);
+
+  bd->buffer [0] = 1;
+
+  sc = rtems_bdbuf_sync(bd);
+  ASSERT_SC(sc);
+
+  sc = rtems_bdbuf_read(dev, BLOCK_WRITE_IO_ERROR, &bd);
+  ASSERT_SC(sc);
+
+  assert(bd->buffer [0] == 0);
+
+  sc = rtems_bdbuf_release(bd);
+  ASSERT_SC(sc);
+
+  /* Check write to deleted disk */
+
+  sc = rtems_bdbuf_read(dev, BLOCK_READ_SUCCESSFUL, &bd);
+  ASSERT_SC(sc);
+
+  sc = rtems_disk_delete(dev);
+  ASSERT_SC(sc);
+
+  sc = rtems_bdbuf_sync(bd);
+  ASSERT_SC(sc);
+
+  printk("*** END OF TEST BLOCK 9 ***\n");
+
+  exit(0);
+}
+
+#define CONFIGURE_INIT
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
+
+#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
+
+#define CONFIGURE_MAXIMUM_TASKS 3
+#define CONFIGURE_MAXIMUM_DRIVERS 4
+#define CONFIGURE_MAXIMUM_SEMAPHORES 5
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_BDBUF_BUFFER_MIN_SIZE BLOCK_SIZE
+#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE BLOCK_SIZE
+#define CONFIGURE_BDBUF_CACHE_MEMORY_SIZE (BLOCK_SIZE * BLOCK_COUNT)
+
+#include <rtems/confdefs.h>
Index: testsuites/libtests/configure.ac
===================================================================
--- testsuites/libtests/configure.ac	(revision c4c8efd02782845db7658b1885a6e509ca15a4f1)
+++ testsuites/libtests/configure.ac	(revision 64734fc14b1015c1568c2906c9aeab1c6a7db82d)
@@ -41,4 +41,6 @@
 block06/Makefile
 block07/Makefile
+block08/Makefile
+block09/Makefile
 bspcmdline01/Makefile
 cpuuse/Makefile
