Index: trunk/kernel/devices/dev_ioc.c
===================================================================
--- trunk/kernel/devices/dev_ioc.c	(revision 647)
+++ trunk/kernel/devices/dev_ioc.c	(revision 657)
@@ -2,5 +2,5 @@
  * dev_ioc.c - IOC (Block Device Controler) generic device API implementation.
  *
- * Author  Alain Greiner    (2016,2017,2018,2019)
+ * Author  Alain Greiner    (2016,2017,2018,2019,2020)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -37,6 +37,6 @@
 extern chdev_directory_t  chdev_dir;     // allocated in kernel_init.c
 
-////////////////////////////////////////
-char * dev_ioc_cmd_str( cmd_type_t cmd )
+////////////////////////////////////////////
+char * dev_ioc_cmd_str( ioc_cmd_type_t cmd )
 {
     if     ( cmd == IOC_READ       )  return "READ";
@@ -91,6 +91,44 @@
 }  // end dev_ioc_init()
 
-///////////////////////////////////////////////
-error_t dev_ioc_move_data( uint32_t   cmd_type,
+////////////////////////////////////////////////////////////////////////////////////
+// This static function executes an asynchronous SYNC_READ or SYNC_WRITE request.
+// thread in the IOC device waiting queue, activates the server thread, blocks on 
+// the THREAD_BLOCKED_IO condition and deschedules.
+// The clent is re-activated by the server thread after IO operation completion.
+////////////////////////////////////////////////////////////////////////////////////
+static error_t dev_ioc_move( uint32_t   cmd_type,
+                             xptr_t     buffer_xp,
+                             uint32_t   lba,
+                             uint32_t   count )
+{
+    thread_t * this = CURRENT_THREAD;              // pointer on client thread
+
+    // get extended pointer on IOC chdev descriptor
+    xptr_t      ioc_xp  = chdev_dir.ioc[0];
+
+// check dev_xp
+assert( (ioc_xp != XPTR_NULL) , "undefined IOC chdev descriptor" );
+
+    // register command in client thread  
+    this->ioc_cmd.dev_xp    = ioc_xp;
+    this->ioc_cmd.type      = cmd_type;
+    this->ioc_cmd.buf_xp    = buffer_xp;
+    this->ioc_cmd.lba       = lba;
+    this->ioc_cmd.count     = count;
+
+    // register client thread in IOC queue, blocks and deschedules 
+    chdev_register_command( ioc_xp );
+
+    // return I/O operation status
+    return this->ioc_cmd.error;
+
+}  // end dev_ioc_move()
+
+////////////////////////////////////////////////////////////////////////////////////
+// This static function executes a synchronous READ or WRITE request.
+// It register the command in the client thread descriptor, and calls directly
+// the driver cmd function.
+////////////////////////////////////////////////////////////////////////////////////
+error_t dev_ioc_sync_move( uint32_t   cmd_type,
                            xptr_t     buffer_xp,
                            uint32_t   lba,
@@ -98,21 +136,4 @@
 {
     thread_t * this = CURRENT_THREAD;              // pointer on client thread
-
-#if ( DEBUG_DEV_IOC_RX  || DEBUG_DEV_IOC_TX )
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-#endif
-
-    // software L2/L3 cache coherence for memory buffer
-    if( chdev_dir.iob )
-    {
-        if( (cmd_type == IOC_SYNC_READ) || (cmd_type == IOC_READ) )
-        {
-            dev_mmc_inval( buffer_xp , count<<9 );
-        }
-        else  // (cmd_type == IOC_SYNC_WRITE) or (cmd_type == IOC_WRITE)
-        {
-            dev_mmc_sync ( buffer_xp , count<<9 );
-        }
-    }
 
     // get extended pointer on IOC chdev descriptor
@@ -129,85 +150,153 @@
     this->ioc_cmd.count     = count;
 
-    // for a synchronous acces, the driver is directly called by the client thread 
-    if( (cmd_type == IOC_SYNC_READ) || (cmd_type == IOC_SYNC_WRITE) )
-    {
-
-#if DEBUG_DEV_IOC_RX
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_SYNC_READ) )
-printk("\n[%s] thread[%x,%x] enters for SYNC_READ / lba  %x / buffer[%x,%x] / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, lba,
-GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
-#endif
-
-#if DEBUG_DEV_IOC_TX
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-if( (DEBUG_DEV_IOC_TX < cycle) && (cmd_type == IOC_SYNC_WRITE) )
-printk("\n[%s] thread[%x,%x] enters for SYNC_WRITE / lba  %x / buffer[%x,%x] / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, lba,
-GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
-#endif
-        // get driver command function
-        cxy_t       ioc_cxy = GET_CXY( ioc_xp );
-        chdev_t   * ioc_ptr = GET_PTR( ioc_xp );
-        dev_cmd_t * cmd = (dev_cmd_t *)hal_remote_lpt( XPTR( ioc_cxy , &ioc_ptr->cmd ) );
-
-        // call driver function
-        cmd( XPTR( local_cxy , this ) );
-
-#if DEBUG_DEV_IOC_RX
-if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_SYNC_READ) )
-printk("\n[%s] thread[%x,%x] resumes for IOC_SYNC_READ\n",
-__FUNCTION__, this->process->pid , this->trdid )
-#endif
-
-#if DEBUG_DEV_IOC_TX
-if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_SYNC_WRITE) )
-printk("\n[%s] thread[%x,%x] resumes for IOC_SYNC_WRITE\n",
-__FUNCTION__, this->process->pid , this->trdid )
-#endif
-
-    }
-    // for an asynchronous access, the client thread registers in the chdev waiting queue,
-    // activates server thread, blocks on THREAD_BLOCKED_IO and deschedules.
-    // It is re-activated by the server thread after IO operation completion.
-    else  // (cmd_type == IOC_READ) || (cmd_type == IOC_WRITE)
-    {
-
-#if DEBUG_DEV_IOC_RX
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_READ) )
-printk("\n[%s] thread[%x,%x] enters for READ / lba  %x / buffer[%x,%x] / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, lba,
-GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
-#endif
-
-#if DEBUG_DEV_IOC_TX
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-if( (DEBUG_DEV_IOC_TX < cycle) && (cmd_type == IOC_WRITE) )
-printk("\n[%s] thread[%x,%x] enters for WRITE / lba  %x / buffer[%x,%x] / cycle %d\n",
-__FUNCTION__ , this->process->pid, this->trdid, lba,
-GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
-#endif
-        chdev_register_command( ioc_xp );
-
-#if(DEBUG_DEV_IOC_RX )
-if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_READ) )
-printk("\n[%s] thread[%x,%x] resumes for IOC_READ\n",
-__FUNCTION__, this->process->pid , this->trdid )
-#endif
-
-#if(DEBUG_DEV_IOC_TX & 1)
-if( (DEBUG_DEV_IOC_RX < cycle) && (cmd_type == IOC_WRITE) )
-printk("\n[%s] thread[%x,%x] resumes for IOC_WRITE\n",
-__FUNCTION__, this->process->pid , this->trdid )
-#endif
-
-    }
+    // get driver command function
+    cxy_t       ioc_cxy = GET_CXY( ioc_xp );
+    chdev_t   * ioc_ptr = GET_PTR( ioc_xp );
+    dev_cmd_t * cmd = (dev_cmd_t *)hal_remote_lpt( XPTR( ioc_cxy , &ioc_ptr->cmd ) );
+
+    // call driver function whithout blocking & descheduling
+    cmd( XPTR( local_cxy , this ) );
 
     // return I/O operation status
     return this->ioc_cmd.error;
 
-}  // end dev_ioc_move_data()
-
-
+}  // end dev_ioc_sync_move()
+
+///////////////////////////////////////////
+error_t dev_ioc_read( xptr_t     buffer_xp,
+                      uint32_t   lba,
+                      uint32_t   count )
+{
+
+#if DEBUG_DEV_IOC_RX
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_DEV_IOC_RX < cycle )
+printk("\n[%s] thread[%x,%x] enters IOC_READ / lba  %x / buffer[%x,%x] / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, lba,
+GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
+#endif
+
+    // software L2/L3 cache coherence for memory buffer
+    if( chdev_dir.iob ) dev_mmc_inval( buffer_xp , count<<9 );
+
+    // request an asynchronous transfer
+    error_t error = dev_ioc_move( IOC_READ,
+                                  buffer_xp,
+                                  lba,
+                                  count );
+#if(DEBUG_DEV_IOC_RX & 1)
+cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_DEV_IOC_RX < cycle )
+printk("\n[%s] thread[%x,%x] exit IOC_READ / cycle %d\n",
+__FUNCTION__, this->process->pid , this->trdid , cycle );
+#endif
+
+    return error;
+
+}  // end dev_ioc_read()
+
+///////////////////////////////////////////
+error_t dev_ioc_write( xptr_t     buffer_xp,
+                       uint32_t   lba,
+                       uint32_t   count )
+{
+
+#if DEBUG_DEV_IOC_TX
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_DEV_IOC_TX < cycle )
+printk("\n[%s] thread[%x,%x] enters IOC_WRITE / lba  %x / buffer[%x,%x] / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, lba,
+GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
+#endif
+
+    // software L2/L3 cache coherence for memory buffer
+    if( chdev_dir.iob ) dev_mmc_sync ( buffer_xp , count<<9 );
+
+    // request a blocking, but asynchronous, transfer
+    error_t error = dev_ioc_move( IOC_WRITE,
+                          buffer_xp,
+                          lba,
+                          count );
+#if(DEBUG_DEV_IOC_TX & 1)
+cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_DEV_IOC_TX < cycle )
+printk("\n[%s] thread[%x,%x] exit IOC_WRITE / cycle %d\n",
+__FUNCTION__, this->process->pid , this->trdid , cycle );
+#endif
+
+    return error;
+
+}  // end dev_ioc_write()
+
+
+///////////////////////////////////////////
+error_t dev_ioc_sync_read( xptr_t     buffer_xp,
+                           uint32_t   lba,
+                           uint32_t   count )
+{
+
+#if DEBUG_DEV_IOC_RX
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_DEV_IOC_RX < cycle )
+printk("\n[%s] thread[%x,%x] enters IOC_SYNC_READ / lba  %x / buffer[%x,%x] / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, lba,
+GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
+#endif
+
+    // software L2/L3 cache coherence for memory buffer
+    if( chdev_dir.iob ) dev_mmc_inval( buffer_xp , count<<9 );
+
+    // request an asynchronous transfer
+    error_t error = dev_ioc_sync_move( IOC_SYNC_READ,
+                                       buffer_xp,
+                                       lba,
+                                       count );
+#if(DEBUG_DEV_IOC_RX & 1)
+cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_DEV_IOC_RX < cycle )
+printk("\n[%s] thread[%x,%x] exit IOC_SYNC_READ / cycle %d\n",
+__FUNCTION__, this->process->pid , this->trdid , cycle );
+#endif
+
+    return error;
+
+}  // end dev_ioc_sync_read()  
+
+/////////////////////////////////////////////////
+error_t dev_ioc_sync_write( xptr_t     buffer_xp,
+                            uint32_t   lba,
+                            uint32_t   count )
+{
+
+#if DEBUG_DEV_IOC_TX
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_DEV_IOC_TX < cycle )
+printk("\n[%s] thread[%x,%x] enters IOC_SYNC_WRITE / lba  %x / buffer[%x,%x] / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, lba,
+GET_CXY(buffer_xp), GET_PTR(buffer_xp), cycle );
+#endif
+
+    // software L2/L3 cache coherence for memory buffer
+    if( chdev_dir.iob ) dev_mmc_sync ( buffer_xp , count<<9 );
+
+    // request a blocking, but asynchronous, transfer
+    error_t error = dev_ioc_sync_move( IOC_SYNC_WRITE,
+                                       buffer_xp,
+                                       lba,
+                                       count );
+#if(DEBUG_DEV_IOC_TX & 1)
+cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_DEV_IOC_TX < cycle )
+printk("\n[%s] thread[%x,%x] exit IOC_SYNC_WRITE / cycle %d\n",
+__FUNCTION__, this->process->pid , this->trdid , cycle );
+#endif
+
+    return error;
+
+}  // end dev_ioc_sync_write() 
+
+
