Index: c/src/libchip/ChangeLog
===================================================================
--- c/src/libchip/ChangeLog	(revision 05341d806f59e022876b65cba7e71b2a55d1dfac)
+++ c/src/libchip/ChangeLog	(revision 5f8394736711a4297b76e8933eaf17f18b3ffafc)
@@ -1,2 +1,9 @@
+2003-03-27	Joel Sherrill <joel@OARcorp.com>
+
+	* ide/Makefile.am: ATA code depends upon libchip/ide which is not
+	allowed in the cpukit source code since it must be buildable
+	independent of any BSP. These files were moved to libchip/ide.
+	* ide/ata.c, ide/ata.h, ide/ata_internal.h: New files.
+
 2003-03-25	Thomas Doerfler <Thomas.Doerfler@imd-systems.de>
 
Index: c/src/libchip/ide/Makefile.am
===================================================================
--- c/src/libchip/ide/Makefile.am	(revision 05341d806f59e022876b65cba7e71b2a55d1dfac)
+++ c/src/libchip/ide/Makefile.am	(revision 5f8394736711a4297b76e8933eaf17f18b3ffafc)
@@ -9,10 +9,10 @@
 LIB = $(ARCH)/$(LIBNAME).a
 
-C_FILES = ide_controller.c
+C_FILES = ata.c ide_controller.c
 C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT))
 
-noinst_HEADERS = 
+noinst_HEADERS = ata_internal.h
 
-include_ide_HEADERS = ide_ctrl_cfg.h ide_ctrl.h ide_ctrl_io.h
+include_ide_HEADERS = ata.h ide_ctrl_cfg.h ide_ctrl.h ide_ctrl_io.h
 
 OBJS = $(C_O_FILES)
Index: c/src/libchip/ide/ata.c
===================================================================
--- c/src/libchip/ide/ata.c	(revision 5f8394736711a4297b76e8933eaf17f18b3ffafc)
+++ c/src/libchip/ide/ata.c	(revision 5f8394736711a4297b76e8933eaf17f18b3ffafc)
@@ -0,0 +1,1316 @@
+/*
+ * ata.c
+ *
+ * ATA RTEMS driver. ATA driver is hardware independant implementation of 
+ * ATA-2 standart, working draft X3T10/0948D, revision 4c. ATA driver bases 
+ * on RTEMS IDE controller driver.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ * 
+ * $Id$
+ * 
+ */
+#include <errno.h>
+#include <chain.h>
+#include <assert.h>
+#include <string.h> /* for "memset" declaration */
+
+#include <rtems/diskdevs.h>
+#include <rtems/blkdev.h>
+#include <libchip/ide_ctrl_io.h>
+#include <libchip/ide_ctrl_cfg.h>
+#include "ata_internal.h"
+#include <libchip/ata.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#define SAFE
+#ifdef SAFE
+typedef rtems_mode preemption_key;
+
+#define DISABLE_PREEMPTION(key) \
+    do {                                                               \
+        rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &(key)); \
+    } while (0)
+
+#define ENABLE_PREEMPTION(key) \
+    do {                                                        \
+        rtems_mode temp;                                        \
+        rtems_task_mode((key), RTEMS_PREEMPT_MASK, &temp);      \
+    } while (0)
+
+#else
+ 
+typedef boolean preemption_key;
+
+#define DISABLE_PREEMPTION(key) \
+    do {                                             \
+        (key) = _Thread_Executing->is_preemptible;   \
+        _Thread_Executing->is_preemptible = 0;       \
+    } while (0)
+    
+#define ENABLE_PREEMPTION(key) \
+    do {                                             \
+        _Thread_Executing->is_preemptible = (key);   \
+        if (_Thread_Evaluate_mode())                 \
+            _Thread_Dispatch();                      \
+    } while (0)
+
+#endif
+
+/* FIXME: case if ATA device is FLASH device need more attention */
+#undef ATA_DEV_IS_FLASH_DISK
+
+/* Block device request with a single buffer provided */
+typedef struct blkdev_request1 {
+    blkdev_request   req;
+    blkdev_sg_buffer sg[1];
+} blkdev_request1;
+
+
+/* Array indexed by controllers minor number */
+static ata_ide_ctrl_t ata_ide_ctrls[IDE_CTRL_MAX_MINOR_NUMBER];
+
+/*
+ * Mapping from ATA-minor numbers to 
+ * controller-minor and device on this controller.
+ */
+static ata_ide_dev_t ata_devs[2 * IDE_CTRL_MAX_MINOR_NUMBER];
+static int ata_devs_number;
+
+/* Flag meaning that ATA driver has already been initialized */
+static rtems_boolean ata_initialized = FALSE;
+
+
+/* task and queue used for asynchronous I/O operations */
+static rtems_id ata_task_id;
+static rtems_id ata_queue_id;
+
+/* Mapping of interrupt vectors to devices */
+static Chain_Control ata_int_vec[ATA_MAX_RTEMS_INT_VEC_NUMBER + 1];  
+
+static void
+ata_process_request(rtems_device_minor_number ctrl_minor);
+
+static void
+ata_process_request_on_init_phase(rtems_device_minor_number  ctrl_minor,
+                                  ata_req_t                 *areq);
+
+static void 
+ata_add_to_controller_queue(rtems_device_minor_number  ctrl_minor, 
+                            ata_req_t                 *areq);
+
+/*
+ * read/write, open/close and ioctl are provided by general block device 
+ * driver. Only initialization and ata-specific ioctl are here.
+ */
+
+/* ata_io_data_request -- 
+ *     Form read/write request for an ATA device and enqueue it to 
+ *     IDE controller. 
+ * 
+ * PARAMETERS:
+ *     device - device identifier
+ *     req    - read/write request from block device driver
+ *
+ * RETURNS:
+ *     RTEMS_SUCCESSFUL on success, or error code if
+ *     error occured 
+ */
+static rtems_status_code
+ata_io_data_request(dev_t device, blkdev_request *req)
+{
+    ata_req_t                 *areq; /* ATA request */
+    rtems_device_minor_number  rel_minor; /* relative minor which indexes 
+                                           * ata_devs array
+                                           */
+    rtems_device_minor_number  ctrl_minor;
+    unsigned8                  dev;
+    
+    rel_minor = (rtems_filesystem_dev_minor_t(device)) / 
+                ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE;
+    
+    /* get controller which serves the ATA device */
+    ctrl_minor = ata_devs[rel_minor].ctrl_minor;
+
+    /* get ATA device identifier (0 or 1) */
+    dev = ata_devs[rel_minor].device;
+
+    areq = malloc(sizeof(ata_req_t));
+    if (areq == NULL)
+    {
+        return RTEMS_NO_MEMORY;
+    }
+                                                            
+    areq->breq = req;
+    areq->cnt = req->count;
+    areq->cbuf = 0;
+    areq->pos = 0;
+    
+    /* set up registers masks */   
+    areq->regs.to_write = ATA_REGISTERS_POSITION;
+    areq->regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
+    
+    /* choose device on the controller for which the command will be issued */
+    areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] = 
+                                    (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS);
+
+    /* Find ATA command and its type */
+    if (ATA_DEV_INFO(ctrl_minor, dev).mode_active & ATA_MODES_DMA)
+    {
+        /* XXX: never has been tested */
+        areq->type = ATA_COMMAND_TYPE_DMA;
+        if (req->req == BLKDEV_REQ_READ)
+            areq->regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_READ_DMA;
+        else 
+            areq->regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_WRITE_DMA;
+    }
+    else 
+    {
+        if (req->req == BLKDEV_REQ_READ)
+        {
+            areq->type = ATA_COMMAND_TYPE_PIO_IN;
+              
+            /* 
+             * choose command to issue: if the number of blocks to be 
+             * exchanged is greater then 1 and for ATA command READ MULTIPLE
+             * data block consists of more then 1 sector choose READ MULTIPLE
+             * otherwise READ SECTORS
+             */
+            areq->regs.regs[IDE_REGISTER_COMMAND] = 
+                ((ATA_DEV_INFO(ctrl_minor, dev).max_multiple) && 
+                 (req->count > 1) && 
+                 (ATA_DEV_INFO(ctrl_minor, dev).current_multiple > 1)) ? 
+                 ATA_COMMAND_READ_MULTIPLE : 
+                 ATA_COMMAND_READ_SECTORS;
+        }
+        else
+        {
+            areq->type = ATA_COMMAND_TYPE_PIO_OUT;
+
+            /* 
+             * choose command to issue: if the number of blocks to be 
+             * exchanged is greater then 1 and for ATA command WRITE MULTIPLE
+             * data block consists of more then 1 sector choose WRITE MULTIPLE
+             * otherwise WRITE SECTORS
+             */
+            areq->regs.regs[IDE_REGISTER_COMMAND] = 
+              ((ATA_DEV_INFO(ctrl_minor, dev).max_multiple) &&
+               (req->count > 1) &&
+               (ATA_DEV_INFO(ctrl_minor, dev).current_multiple > 1)) ? 
+               ATA_COMMAND_WRITE_MULTIPLE : 
+               ATA_COMMAND_WRITE_SECTORS;
+        }
+    }
+
+    /*
+     * Fill position registers
+     */
+    if (ATA_DEV_INFO(ctrl_minor, dev).lba_avaible)
+    {
+        areq->regs.regs[IDE_REGISTER_LBA0] = (unsigned8)req->start;
+        areq->regs.regs[IDE_REGISTER_LBA1] = (unsigned8)(req->start >> 8);
+        areq->regs.regs[IDE_REGISTER_LBA2] = (unsigned8)(req->start >> 16);
+        areq->regs.regs[IDE_REGISTER_LBA3] |= (unsigned8) (req->start >> 24);
+        areq->regs.regs[IDE_REGISTER_LBA3] |= IDE_REGISTER_LBA3_L;
+    }
+    else
+    {
+        unsigned32 count = req->start;
+
+        areq->regs.regs[IDE_REGISTER_SECTOR_NUMBER] =
+                        (count % ATA_DEV_INFO(ctrl_minor, dev).sectors) + 1;
+
+        /* now count = number of tracks: */
+        count /= ATA_DEV_INFO(ctrl_minor, dev).sectors;
+        areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] |= 
+                          (count / ATA_DEV_INFO(ctrl_minor, dev).cylinders);
+
+        /* now count = number of cylinders */
+        count %= ATA_DEV_INFO(ctrl_minor, dev).cylinders;
+        areq->regs.regs[IDE_REGISTER_CYLINDER_LOW] = (unsigned8)count;
+        areq->regs.regs[IDE_REGISTER_CYLINDER_HIGH] = (unsigned8)(count >> 8);
+        areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &= 
+                                                ~IDE_REGISTER_DEVICE_HEAD_L;
+    }
+
+    /* fill sector count register */
+    areq->regs.regs[IDE_REGISTER_SECTOR_COUNT] = areq->breq->count;
+    
+    /* add request to the queue of awaiting requests to the controller */
+    ata_add_to_controller_queue(ctrl_minor, areq);
+ 
+    return RTEMS_SUCCESSFUL;
+}
+
+/* ata_non_data_request -- 
+ *     Form and serve request of NON DATA type for an ATA device. 
+ *     Processing of NON DATA request is SYNChronous operation.
+ * 
+ * PARAMETERS:
+ *     device - device identifier
+ *     cmd    - command
+ *     argp   - arguments for command
+ *
+ * RETURNS:
+ *     RTEMS_SUCCESSFUL on success, or error code if
+ *     error occured 
+ */
+static rtems_status_code
+ata_non_data_request(dev_t device, int cmd, void *argp)
+{
+    rtems_status_code          rc;
+    ata_req_t                 *areq;       /* ATA request */
+    rtems_device_minor_number  rel_minor; /* relative minor which indexes
+                                           * ata_devs array
+                                           */
+    rtems_device_minor_number  ctrl_minor;
+    unsigned8                  dev;
+    ata_queue_msg_t            msg;    
+    
+    rel_minor = (rtems_filesystem_dev_minor_t(device)) /
+                ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE; 
+
+    /* get controller which serves the ATA device */
+    ctrl_minor = ata_devs[rel_minor].ctrl_minor;
+
+    /* get ATA device identifier (0 or 1) */
+    dev = ata_devs[rel_minor].device;
+
+    /* form the request */
+    areq = malloc(sizeof(ata_req_t));
+    if (areq == NULL)
+    {
+        return RTEMS_NO_MEMORY;
+    }
+    memset(areq, 0, sizeof(ata_req_t));    
+
+    areq->type = ATA_COMMAND_TYPE_NON_DATA;
+    areq->regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
+    areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] |= 
+                                    (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS);
+    areq->breq = NULL;
+    areq->regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_ERROR);
+    
+    /* 
+     * depending on command fill command register and additional registers 
+     * which are needed for command execution
+     */
+    switch(cmd)
+    { 
+        case ATAIO_SET_MULTIPLE_MODE:
+            areq->regs.regs[IDE_REGISTER_COMMAND] = 
+                                                ATA_COMMAND_SET_MULTIPLE_MODE;
+            areq->regs.to_write |= 
+                               ATA_REGISTERS_VALUE(IDE_REGISTER_SECTOR_COUNT);
+            areq->regs.regs[IDE_REGISTER_SECTOR_COUNT] = *(unsigned8 *)argp;
+            break;
+        
+        default:
+            free(areq);
+            return RTEMS_INVALID_NUMBER;
+            break;                                
+    }  
+
+    rc = rtems_semaphore_create(rtems_build_name('I', 'D', 'E', 'S'), 
+                                0, 
+                                RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | 
+                                RTEMS_NO_INHERIT_PRIORITY |
+                                RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
+                                0,
+                                &(areq->sema));
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        free(areq);
+        return rc;
+    }                                 
+                                        
+    ata_add_to_controller_queue(ctrl_minor, areq);
+    
+    /* wait for request processing... */
+    rc = rtems_semaphore_obtain(areq->sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        free(areq);
+        return rc;
+    }                                 
+
+    rtems_semaphore_delete(areq->sema);
+    
+    /* 
+     * if no error occurred and if necessary, update internal ata driver data 
+     * structures to reflect changes (in device configuration, for example)
+     */ 
+    if (areq->status == RTEMS_SUCCESSFUL)
+    {
+        switch(cmd)
+        { 
+            case ATAIO_SET_MULTIPLE_MODE:
+                ATA_DEV_INFO(ctrl_minor, dev).current_multiple = 
+                                                           *(unsigned8 *)argp;
+                break;
+        
+            default:
+                rc = RTEMS_INVALID_NUMBER;
+                break;                                
+        }  
+    }    
+    else    
+    {    
+        /* XXX: should be correct error processing: for ex, may be 
+         * ABRT and then we should return RTEMS_NOT_IMPLEMENTED
+         */
+        rc = RTEMS_IO_ERROR;
+    }    
+    
+    /* tell ata driver that controller ready to serve next request */
+    ATA_SEND_EVT(msg, ATA_MSG_SUCCESS_EVT, ctrl_minor, 0);
+                                                 
+    return rc;
+}
+
+/* ata_process_request -- 
+ *     Get first request from controller's queue and process it. 
+ * 
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *
+ * RETURNS:
+ *     NONE 
+ */
+static void
+ata_process_request(rtems_device_minor_number ctrl_minor)
+{
+    ata_req_t       *areq;
+    unsigned16       byte; /* emphasize that only 8 low bits is meaningful */
+    ata_queue_msg_t  msg;
+    unsigned8        i, dev;
+    unsigned16       val;
+    unsigned16       data_bs; /* the number of 512-bytes sectors in one 
+                               * data block 
+                               */
+    ISR_Level        level;                           
+        
+    /* if no requests to controller then do nothing */
+    if (Chain_Is_empty(&ata_ide_ctrls[ctrl_minor].reqs))
+        return;
+
+    /* get first request in the controller's queue */
+    _ISR_Disable(level);
+    areq = (ata_req_t *)(ata_ide_ctrls[ctrl_minor].reqs.first);
+    _ISR_Enable(level);
+    
+    /* get ATA device identifier (0 or 1) */
+    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] & 
+           IDE_REGISTER_DEVICE_HEAD_DEV;
+
+    /* get data block size */
+    data_bs = ATA_DEV_INFO(ctrl_minor, dev).current_multiple ?  
+              ATA_DEV_INFO(ctrl_minor, dev).current_multiple : 1;      
+    
+    /* execute device select protocol */
+    ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD, 
+                                  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
+    
+    do {
+        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
+    } while ((byte & IDE_REGISTER_STATUS_BSY) || 
+             (!(byte & IDE_REGISTER_STATUS_DRDY)));
+
+    /* fill in all  necessary registers on the controller */
+    for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
+    {
+        unsigned32 reg = (1 << i);
+        if (areq->regs.to_write & reg)
+            ide_controller_write_register(ctrl_minor, i, areq->regs.regs[i]);
+    }
+
+    /* continue to execute ATA protocols depending on type of request */
+    if (areq->type == ATA_COMMAND_TYPE_PIO_OUT)
+    {
+        do {
+            ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, 
+                                         &byte);
+        } while (byte & IDE_REGISTER_STATUS_BSY);
+
+        if (byte & IDE_REGISTER_STATUS_DRQ)
+        {
+            ide_controller_write_data_block(
+                ctrl_minor, 
+                MIN(data_bs, areq->cnt) * ATA_SECTOR_SIZE,
+                areq->breq->bufs, &areq->cbuf,
+                &areq->pos);
+            areq->cnt -= MIN(data_bs, areq->cnt);
+        }    
+        else
+        {    
+            if (IDE_Controller_Table[ctrl_minor].int_driven == 0)
+            {
+                ide_controller_read_register(
+                    ctrl_minor, 
+                    IDE_REGISTER_ALTERNATE_STATUS_OFFSET,
+                    &val);
+                ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS,
+                                             &val);
+
+                ATA_SEND_EVT(msg, ATA_MSG_ERROR_EVT, ctrl_minor, 
+                             RTEMS_IO_ERROR);
+            }
+        }    
+    }
+
+    if (IDE_Controller_Table[ctrl_minor].int_driven == 0)
+    {
+        do {
+            ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, 
+                                         &byte);
+        } while (byte & IDE_REGISTER_STATUS_BSY);
+        
+        ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, ctrl_minor, 0);
+    }    
+}
+
+/* ata_request_done -- 
+ *     Extract request from controller queue, execute callback if necessary
+ *     and process next request for the controller.
+ * 
+ * PARAMETERS:
+ *     areq       - ATA request 
+ *     ctrl_minor - controller identifier
+ *     status     - status with which request has been done
+ *     error      - error, if status != RTEMS_SUCCESSFUL
+ *
+ * RETURNS:
+ *     NONE
+ */
+static inline void
+ata_request_done(ata_req_t *areq, rtems_device_minor_number ctrl_minor,
+                 rtems_status_code status, int error)
+{
+    preemption_key key;
+
+    assert(areq);
+
+    DISABLE_PREEMPTION(key);
+    ATA_EXEC_CALLBACK(areq, status, error);
+    Chain_Extract(&areq->link);
+    free(areq);
+
+    if (!Chain_Is_empty(&ata_ide_ctrls[ctrl_minor].reqs))
+    {
+        ENABLE_PREEMPTION(key);
+        ata_process_request(ctrl_minor);
+        return;
+    }
+    ENABLE_PREEMPTION(key); 
+}
+
+/* ata_non_data_request_done -- 
+ *     Set up request status and release request's semaphore.
+ * 
+ * PARAMETERS:
+ *     areq       - ATA request 
+ *     ctrl_minor - controller identifier
+ *     status     - status with which request has been done
+ *     error      - error, if status != RTEMS_SUCCESSFUL
+ *
+ * RETURNS:
+ *     NONE
+ */
+static inline void
+ata_non_data_request_done(ata_req_t *areq, 
+                          rtems_device_minor_number ctrl_minor,
+                          rtems_status_code status, int error)
+{
+    areq->status = status;
+    areq->error = error;
+    rtems_semaphore_release(areq->sema);
+}
+
+
+/* ata_add_to_controller_queue -- 
+ *     Add request to the controller's queue.
+ * 
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *     areq       - ATA request 
+ *
+ * RETURNS:
+ *     NONE
+ */
+static void
+ata_add_to_controller_queue(rtems_device_minor_number  ctrl_minor, 
+                            ata_req_t                 *areq)
+{
+    Chain_Append(&ata_ide_ctrls[ctrl_minor].reqs, &areq->link);
+    if (Chain_Has_only_one_node(&ata_ide_ctrls[ctrl_minor].reqs))
+    {
+        unsigned16      val;
+        ata_queue_msg_t msg;
+
+#ifdef DEBUG
+        /* 
+         * read IDE_REGISTER_ALTERNATE_STATUS instead IDE_REGISTER_STATUS
+         * to prevent clearing of pending interrupt
+         */
+        ide_controller_read_register(ctrl_minor, 
+                                     IDE_REGISTER_ALTERNATE_STATUS, 
+                                     &val);
+        if (val & IDE_REGISTER_STATUS_BSY)
+            return;
+#endif
+        ATA_SEND_EVT(msg, ATA_MSG_PROCESS_NEXT_EVT, ctrl_minor, 0);
+    }    
+}                            
+
+
+/* ata_interrupt_handler -- 
+ *     ATA driver interrrupt handler. If interrrupt happend it mapped it to
+ *     controller (controllerS, if a number of controllers share one int line)
+ *     and generates ATA event(s).
+ * 
+ * PARAMETERS:
+ *     vec - interrupt vector  
+ *
+ * RETURNS:
+ *     NONE
+ */
+rtems_isr
+ata_interrupt_handler(rtems_vector_number vec)
+{
+    Chain_Node      *the_node = ((Chain_Control *)(&ata_int_vec[vec]))->first;
+    ata_queue_msg_t  msg;
+    unsigned16       byte; /* emphasize that only 8 low bits is meaningful */
+    
+    for ( ; !Chain_Is_tail(&ata_int_vec[vec], the_node) ; )
+    {
+        /* if (1) - is temporary hack - currently I don't know how to identify
+         * controller which asserted interrupt if few controllers share one
+         * interrupt line
+         */
+        if (1)
+        {
+            msg.ctrl_minor = ((ata_int_st_t *)the_node)->ctrl_minor;
+            ide_controller_read_register(msg.ctrl_minor, IDE_REGISTER_STATUS, 
+                                         &byte);
+            ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, msg.ctrl_minor, 0);                             
+        }
+        the_node = the_node->next;
+    }   
+}
+
+/* ata_pio_in_protocol -- 
+ *     ATA PIO_IN protocol implementation, see specification
+ * 
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *     areq       - ATA request 
+ *
+ * RETURNS:
+ *     NONE
+ */
+static inline void
+ata_pio_in_protocol(rtems_device_minor_number ctrl_minor, ata_req_t *areq)
+{
+    unsigned16      bs, val;
+    unsigned8       dev;
+    unsigned32      min_val;
+    ata_queue_msg_t msg;
+        
+    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] & 
+           IDE_REGISTER_DEVICE_HEAD_DEV;
+
+    bs = ATA_DEV_INFO(ctrl_minor, dev).current_multiple ?  
+         ATA_DEV_INFO(ctrl_minor, dev).current_multiple : 1;      
+    min_val = MIN(bs, areq->cnt);
+    
+    ide_controller_read_data_block(ctrl_minor, min_val * ATA_SECTOR_SIZE, 
+                                   areq->breq->bufs, &areq->cbuf, &areq->pos);
+              
+    areq->cnt -= min_val;
+    if (areq->cnt == 0)
+    {
+        ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL, RTEMS_SUCCESSFUL);
+    }
+    else if (IDE_Controller_Table[ctrl_minor].int_driven == 0)
+    {
+        do {
+           ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
+        } while (val & IDE_REGISTER_STATUS_BSY);
+        
+        ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, ctrl_minor, 0);
+    }
+}
+
+/* ata_pio_out_protocol -- 
+ *     ATA PIO_OUT protocol implementation, see specification
+ * 
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *     areq       - ATA request 
+ *
+ * RETURNS:
+ *     NONE
+ */
+static inline void
+ata_pio_out_protocol(rtems_device_minor_number ctrl_minor, ata_req_t *areq)
+{
+    unsigned16      bs, val;
+    unsigned8       dev;
+    unsigned32      min_val;
+    ata_queue_msg_t msg;
+    
+    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] & 
+           IDE_REGISTER_DEVICE_HEAD_DEV;
+
+    bs = ATA_DEV_INFO(ctrl_minor, dev).current_multiple ?  
+         ATA_DEV_INFO(ctrl_minor, dev).current_multiple : 1;      
+
+    min_val = MIN(bs, areq->cnt);     
+
+    if (areq->cnt == 0)
+    {
+        ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL, RTEMS_SUCCESSFUL);
+    }
+    else 
+    {
+        ide_controller_write_data_block(ctrl_minor, min_val * ATA_SECTOR_SIZE,
+                                        areq->breq->bufs, &areq->cbuf, 
+                                        &areq->pos);
+        areq->cnt -= min_val;
+        if (IDE_Controller_Table[ctrl_minor].int_driven == 0)
+        {
+            do {
+                ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, 
+                                             &val);
+            } while (val & IDE_REGISTER_STATUS_BSY);
+
+            ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, ctrl_minor, 0);
+        }
+  }
+}
+
+/* ata_queue_task -- 
+ *     Task which manages ATA driver events queue.
+ * 
+ * PARAMETERS:
+ *     arg - ignored
+ *
+ * RETURNS:
+ *     NONE
+ *
+ * NOTES:
+ *     should be non-preemptive 
+ */
+static rtems_task
+ata_queue_task(rtems_task_argument arg)
+{
+    ata_queue_msg_t            msg;
+    rtems_unsigned32           size;
+    ata_req_t                 *areq;
+    rtems_device_minor_number  ctrl_minor;
+    unsigned16                 val;
+    unsigned16                 val1;
+    rtems_status_code          rc;
+    ISR_Level                  level;
+
+    while (1)
+    {
+        /* get event which has happend */
+        rc = rtems_message_queue_receive(ata_queue_id, &msg, &size, RTEMS_WAIT, 
+                                         RTEMS_NO_TIMEOUT);
+        if (rc != RTEMS_SUCCESSFUL)
+            rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
+                                             
+        /* get controller on which event has happend */
+        ctrl_minor = msg.ctrl_minor;
+        
+        /* get current request to the controller */
+        _ISR_Disable(level);        
+        areq = (ata_req_t *)(ata_ide_ctrls[ctrl_minor].reqs.first);
+        _ISR_Enable(level);
+        
+        switch(msg.type)
+        {
+            case ATA_MSG_PROCESS_NEXT_EVT:
+                /* process next request in the controller queue */
+                ata_process_request(ctrl_minor);
+                break;
+
+            case ATA_MSG_SUCCESS_EVT:
+                /* 
+                 * finish processing of current request with successful 
+                 * status and start processing of the next request in the 
+                 * controller queue
+                 */
+                ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL, 
+                                 msg.error);
+                break;
+                
+            case ATA_MSG_ERROR_EVT:
+                /* 
+                 * finish processing of current request with error 
+                 * status and start processing of the next request in the 
+                 * controller queue
+                 */
+                ata_request_done(areq, ctrl_minor, RTEMS_UNSATISFIED, 
+                                 msg.error);
+                break;
+                
+            case ATA_MSG_GEN_EVT:
+                /* 
+                 * continue processing of the current request to the 
+                 * controller according to current request state and 
+                 * ATA protocol
+                 */
+                ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, 
+                                           &val);
+                /* process error case */
+                if (val & IDE_REGISTER_STATUS_ERR)
+                { 
+                    ide_controller_read_register(ctrl_minor, 
+                                                 IDE_REGISTER_ERROR, 
+                                                 &val);
+                    if (areq->type == ATA_COMMAND_TYPE_NON_DATA)
+                        ata_non_data_request_done(areq, ctrl_minor, 
+                                                  RTEMS_UNSATISFIED, 
+                                                  RTEMS_IO_ERROR);
+                    else                             
+                        ata_request_done(areq, ctrl_minor, RTEMS_UNSATISFIED, 
+                                         RTEMS_IO_ERROR);
+                    break;                                  
+                }
+
+                switch(areq->type)
+                {
+                    case ATA_COMMAND_TYPE_PIO_IN:
+                        ata_pio_in_protocol(ctrl_minor, areq);
+                        break;
+                
+                    case ATA_COMMAND_TYPE_PIO_OUT:
+                        ata_pio_out_protocol(ctrl_minor, areq);
+                        break;
+                
+                    case ATA_COMMAND_TYPE_NON_DATA:
+                        ide_controller_read_register(ctrl_minor, 
+                                                      IDE_REGISTER_ERROR, 
+                                                     &val1);
+                        ata_non_data_request_done(areq, ctrl_minor,
+                                                  RTEMS_SUCCESSFUL,
+                                                  val1);
+                        break;
+            
+                    default:
+                        printf("ata_queue_task: non-supported command type\n");
+                        ata_request_done(areq, ctrl_minor,
+                                         RTEMS_UNSATISFIED,
+                                         RTEMS_NOT_IMPLEMENTED);
+                        break;          
+                }
+                break;    
+
+            default:
+                rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
+                break;
+        }
+    }
+}
+
+/* ata_ioctl -- 
+ *     ATA driver ioctl interface.
+ * 
+ * PARAMETERS:
+ *     device - device identifier
+ *     cmd    - command
+ *     argp   - arguments
+ *
+ * RETURNS:
+ *     depend on 'cmd'
+ */
+int 
+ata_ioctl(dev_t device, int cmd, void *argp)
+{
+    rtems_status_code         status;
+    rtems_device_minor_number rel_minor;
+    
+    rel_minor = (rtems_filesystem_dev_minor_t(device)) /
+                ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE;
+
+    /* 
+     * in most cases this means that device 'device' is not an registred ATA
+     * device
+     */ 
+    if (ata_devs[rel_minor].device == ATA_UNDEFINED_VALUE)
+    {
+        errno = ENODEV;
+        return -1;
+    }    
+
+    switch (cmd) 
+    {
+        case BLKIO_REQUEST:
+            status = ata_io_data_request(device, (blkdev_request *)argp);
+            break;
+        
+        case ATAIO_SET_MULTIPLE_MODE:
+            status = ata_non_data_request(device, cmd, argp);
+            break;
+      
+        default:
+            errno = EBADRQC;
+            return -1;
+            break;
+    }
+
+    if (status != RTEMS_SUCCESSFUL)
+    {
+        errno = EIO;
+        return -1; 
+    }
+    return 0;
+}
+
+/*
+ * ata_initialize --
+ *     Initializes all ATA devices found on initialized IDE controllers.
+ * 
+ * PARAMETERS:
+ *     major - device major number
+ *     minor - device minor number
+ *     args   - arguments
+ *
+ * RETURNS:
+ *     RTEMS_SUCCESSFUL on success, or error code if
+ *     error occured 
+ */
+rtems_device_driver 
+ata_initialize(rtems_device_major_number major, 
+               rtems_device_minor_number minor_arg, 
+               void *args)
+{
+    unsigned32         ctrl_minor;
+    rtems_status_code  status;
+    ata_req_t          areq;
+    blkdev_request1    breq;     
+    unsigned8          i, dev = 0;
+    unsigned16        *buffer;
+    unsigned16         ec;
+    char               name[ATA_MAX_NAME_LENGTH];
+    dev_t              device;
+    ata_int_st_t      *int_st;
+    rtems_isr_entry    old_isr;
+
+    if (ata_initialized)
+        return RTEMS_SUCCESSFUL;
+            
+    /* initialization of disk devices library */
+    status = rtems_disk_io_initialize();
+    if (status != RTEMS_SUCCESSFUL)
+        return status;
+        
+    /* create queue for asynchronous requests handling */
+    status = rtems_message_queue_create(
+                 rtems_build_name('A', 'T', 'A', 'Q'),
+                 ATA_DRIVER_MESSAGE_QUEUE_SIZE,
+                 sizeof(ata_queue_msg_t),
+                 RTEMS_FIFO | RTEMS_LOCAL,
+                 &ata_queue_id);
+    if (status != RTEMS_SUCCESSFUL)
+    {
+        rtems_disk_io_done();
+        return status;
+    }    
+
+    /* 
+     * create ATA driver task, see comments for task implementation for 
+     * details 
+     */
+    status = rtems_task_create(
+                 rtems_build_name ('A', 'T', 'A', 'T'),
+                 ATA_DRIVER_TASK_PRIORITY,
+                 ATA_DRIVER_TASK_STACK_SIZE,
+                 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_ASR | 
+                 RTEMS_INTERRUPT_LEVEL(0),
+                 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
+                 &ata_task_id);
+    if (status != RTEMS_SUCCESSFUL)
+    {
+        rtems_message_queue_delete(ata_queue_id);
+        rtems_disk_io_done();
+        return status;
+    }    
+    
+    /* 
+     * start ATA driver task. Actually the task will not start immediately - 
+     * it will start only after multitasking support will be started
+     */ 
+    status = rtems_task_start(ata_task_id, ata_queue_task, 0); 
+    if (status != RTEMS_SUCCESSFUL)
+    {
+        rtems_task_delete(ata_task_id);
+        rtems_message_queue_delete(ata_queue_id);
+        rtems_disk_io_done();
+        return status;
+    }    
+    
+    buffer = (unsigned16 *)malloc(ATA_SECTOR_SIZE);
+    if (buffer == NULL)
+    {
+        rtems_task_delete(ata_task_id);
+        rtems_message_queue_delete(ata_queue_id);
+        rtems_disk_io_done();
+        return RTEMS_NO_MEMORY;
+    }    
+        
+    ata_devs_number = 0;
+
+    for (i = 0; i < (2 * IDE_CTRL_MAX_MINOR_NUMBER); i++)
+        ata_devs[i].device = ATA_UNDEFINED_VALUE;
+
+    /* prepare ATA driver for handling  interrupt driven devices */
+    for (i = 0; i < ATA_MAX_RTEMS_INT_VEC_NUMBER; i++)
+        Chain_Initialize_empty(&ata_int_vec[i]);
+
+    /* 
+     * during ATA driver initialization EXECUTE DEVICE DIAGNOSTIC and 
+     * IDENTIFY DEVICE ATA command should be issued; for these purposes ATA 
+     * requests should be formed; ATA requests contain block device request, 
+     * so form block device request first
+     */
+    memset(&breq, 0, sizeof(blkdev_request1));
+    breq.req.req_done = NULL;
+    breq.req.done_arg = &breq;
+    breq.req.bufnum = 1;
+    breq.req.count = 1;
+    breq.req.bufs[0].length = ATA_SECTOR_SIZE;
+    breq.req.bufs[0].buffer = buffer;
+
+    /* 
+     * for each presented IDE controller execute EXECUTE DEVICE DIAGNOSTIC
+     * ATA command; for each found device execute IDENTIFY DEVICE ATA 
+     * command 
+     */
+    for (ctrl_minor = 0; ctrl_minor < IDE_Controller_Count; ctrl_minor++)
+    if (IDE_Controller_Table[ctrl_minor].status == IDE_CTRL_INITIALIZED)
+    {
+        Chain_Initialize_empty(&ata_ide_ctrls[ctrl_minor].reqs);
+        
+        if (IDE_Controller_Table[ctrl_minor].int_driven == TRUE)
+        {
+            int_st = malloc(sizeof(ata_int_st_t));
+            if (int_st == NULL)
+            {
+                free(buffer);
+                rtems_task_delete(ata_task_id);
+                rtems_message_queue_delete(ata_queue_id);
+                rtems_disk_io_done();
+                return RTEMS_NO_MEMORY;
+            }       
+
+            int_st->ctrl_minor = ctrl_minor;
+
+            status = rtems_interrupt_catch(
+                         ata_interrupt_handler, 
+                         IDE_Controller_Table[ctrl_minor].int_vec, 
+                         &old_isr);
+            if (status != RTEMS_SUCCESSFUL)
+            {
+                free(int_st);
+                free(buffer);
+                rtems_task_delete(ata_task_id);
+                rtems_message_queue_delete(ata_queue_id);
+                rtems_disk_io_done();
+                return status;
+            } 
+            Chain_Append(
+                &ata_int_vec[IDE_Controller_Table[ctrl_minor].int_vec],
+                &int_st->link);
+
+            /* disable interrupts */
+            ide_controller_write_register(ctrl_minor, 
+                                          IDE_REGISTER_DEVICE_CONTROL_OFFSET, 
+                                          IDE_REGISTER_DEVICE_CONTROL_nIEN);
+        }
+
+        /*
+         * Issue EXECUTE DEVICE DIAGNOSTIC ATA command for explore is
+         * there any ATA device on the controller.
+         */
+        memset(&areq, 0, sizeof(ata_req_t));
+        areq.type = ATA_COMMAND_TYPE_NON_DATA;
+        areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
+        areq.regs.regs[IDE_REGISTER_COMMAND] = 
+                                  ATA_COMMAND_EXECUTE_DEVICE_DIAGNOSTIC;
+        areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_ERROR);
+
+        areq.breq = (blkdev_request *)&breq;
+
+        /* 
+         * Process the request. Special processing of requests on 
+         * initialization phase is needed because at this moment there 
+         * is no multitasking enviroment
+         */
+        ata_process_request_on_init_phase(ctrl_minor, &areq);
+
+        /*
+         * check status of I/O operation
+         */
+        if (breq.req.status != RTEMS_SUCCESSFUL)
+            continue;
+      
+        /* disassemble returned diagnostic codes */ 
+        if (breq.req.error == ATA_DEV0_PASSED_DEV1_PASSED_OR_NOT_PRSNT)
+        {
+            ATA_DEV_INFO(ctrl_minor, 0).present = 1;
+            ATA_DEV_INFO(ctrl_minor,1).present = 1; 
+        }
+        else if (breq.req.error == ATA_DEV0_PASSED_DEV1_FAILED)
+        {
+            ATA_DEV_INFO(ctrl_minor,0).present = 1;
+            ATA_DEV_INFO(ctrl_minor,1).present = 0;
+        }
+        else if (breq.req.error < ATA_DEV1_PASSED_DEV0_FAILED)
+        {
+            ATA_DEV_INFO(ctrl_minor,0).present = 0;
+            ATA_DEV_INFO(ctrl_minor,1).present = 1;
+        }
+        else
+        {
+            ATA_DEV_INFO(ctrl_minor, 0).present = 0;
+            ATA_DEV_INFO(ctrl_minor, 1).present = 0;
+        }
+
+        /* refine the returned codes */
+        if (ATA_DEV_INFO(ctrl_minor, 1).present != 0)
+        {
+            ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &ec);
+            if (ec & ATA_DEV1_PASSED_DEV0_FAILED)
+                ATA_DEV_INFO(ctrl_minor, 1).present = 1;
+            else
+                ATA_DEV_INFO(ctrl_minor, 1).present = 0;
+        }
+
+        /* for each found ATA device obtain it configuration */
+        for (dev = 0; dev < 2; dev++)
+        if (ATA_DEV_INFO(ctrl_minor, dev).present)
+        {
+            /*
+             * Issue DEVICE IDENTIFY ATA command and get device 
+             * configuration           
+             */
+            memset(&areq, 0, sizeof(ata_req_t));
+            areq.type = ATA_COMMAND_TYPE_PIO_IN;
+            areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
+            areq.regs.regs[IDE_REGISTER_COMMAND] = 
+                                              ATA_COMMAND_IDENTIFY_DEVICE;
+            areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
+            areq.breq = (blkdev_request *)&breq;
+            
+            areq.cnt = breq.req.count;
+
+            areq.regs.regs[IDE_REGISTER_DEVICE_HEAD] |=
+                                    (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS);
+
+            /* 
+             * Process the request. Special processing of requests on 
+             * initialization phase is needed because at this moment there 
+             * is no multitasking enviroment
+             */
+            ata_process_request_on_init_phase(ctrl_minor, &areq);
+
+            /* check status of I/O operation */
+            if (breq.req.status != RTEMS_SUCCESSFUL)
+                continue;
+
+            /*
+             * Parse returned device configuration and fill in ATA internal 
+             * device info structure
+             */
+            ATA_DEV_INFO(ctrl_minor, dev).cylinders = 
+                CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
+            ATA_DEV_INFO(ctrl_minor, dev).heads = 
+                CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
+            ATA_DEV_INFO(ctrl_minor, dev).sectors = 
+                CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
+            ATA_DEV_INFO(ctrl_minor, dev).lba_sectors = 
+                (CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]) << 16) + 
+                 CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
+            ATA_DEV_INFO(ctrl_minor, dev).lba_avaible = 
+                (CF_LE_W(buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
+            ATA_DEV_INFO(ctrl_minor, dev).max_multiple = 
+                (unsigned8) (CF_LE_W(buffer[ATA_IDENT_WORD_RW_MULT]));
+            ATA_DEV_INFO(ctrl_minor, dev).current_multiple = 
+                (CF_LE_W(buffer[ATA_IDENT_WORD_MULT_SECS]) & 0x100) ? 
+                (unsigned8)(CF_LE_W(buffer[ATA_IDENT_WORD_MULT_SECS])) :
+                 0;
+
+            if ((CF_LE_W(buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) & 
+                 ATA_IDENT_BIT_VALID) == 0) {
+	      /* no "supported modes" info -> use default */
+	      ATA_DEV_INFO(ctrl_minor, dev).mode_active = ATA_MODES_PIO3;
+	    }
+	    else {
+	      ATA_DEV_INFO(ctrl_minor, dev).modes_avaible =
+		((CF_LE_W(buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
+		((CF_LE_W(buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
+		((CF_LE_W(buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
+		((CF_LE_W(buffer[63]) & 0x2) ? 
+		 ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
+		((CF_LE_W(buffer[63]) & 0x4) ? 
+		 ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
+	      if (ATA_DEV_INFO(ctrl_minor, dev).modes_avaible == 0)
+                continue;
+	      /* 
+	       * choose most appropriate ATA device data I/O speed supported
+	       * by the controller
+	       */
+	      status = ide_controller_config_io_speed(
+                ctrl_minor, 
+                ATA_DEV_INFO(ctrl_minor, dev).modes_avaible);
+	      if (status != RTEMS_SUCCESSFUL)
+                continue;
+	    }      
+            /*
+             * Ok, let register new ATA device in the system
+             */
+            ata_devs[ata_devs_number].ctrl_minor = ctrl_minor;
+            ata_devs[ata_devs_number].device = dev;
+
+            snprintf(name, ATA_MAX_NAME_LENGTH, "/dev/hd%c", 
+                     'a' + 2 * ctrl_minor + dev);
+            device = rtems_filesystem_make_dev_t(
+                         major, 
+                         (ata_devs_number * 
+                          ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE));
+
+            status = rtems_disk_create_phys(device, ATA_SECTOR_SIZE, 
+                ATA_DEV_INFO(ctrl_minor, dev).lba_avaible ? 
+                ATA_DEV_INFO(ctrl_minor, dev).lba_sectors : 
+                (ATA_DEV_INFO(ctrl_minor, dev).heads *
+                 ATA_DEV_INFO(ctrl_minor, dev).cylinders *
+                 ATA_DEV_INFO(ctrl_minor, dev).sectors),
+                (block_device_ioctl) ata_ioctl, name);
+            if (status != RTEMS_SUCCESSFUL)
+            {
+                ata_devs[ata_devs_number].device = ATA_UNDEFINED_VALUE;
+                continue;
+            }       
+            ata_devs_number++;
+        }
+        if (IDE_Controller_Table[ctrl_minor].int_driven == TRUE)
+        {    
+            ide_controller_write_register(ctrl_minor, 
+                                          IDE_REGISTER_DEVICE_CONTROL_OFFSET, 
+                                          0x00);
+        }
+    }
+
+    free(buffer);
+    ata_initialized = TRUE;
+    return RTEMS_SUCCESSFUL;
+}
+
+/* ata_process_request_on_init_phase -- 
+ *     Process the ATA request during system initialization. Request 
+ *     processing is syncronous and doesn't use multiprocessing enviroment.
+ * 
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *     areq       - ATA request
+ *
+ * RETURNS:
+ *     NONE 
+ */
+static void
+ata_process_request_on_init_phase(rtems_device_minor_number  ctrl_minor,
+                                  ata_req_t                 *areq)
+{
+    unsigned16         byte;/* emphasize that only 8 low bits is meaningful */
+    unsigned8          i, dev;
+    unsigned16         val, val1;
+    unsigned16         data_bs; /* the number of 512 bytes sectors into one 
+                                 * data block 
+                                 */
+    assert(areq);
+    
+    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] & 
+           IDE_REGISTER_DEVICE_HEAD_DEV;
+
+    data_bs = ATA_DEV_INFO(ctrl_minor, dev).current_multiple ?  
+              ATA_DEV_INFO(ctrl_minor, dev).current_multiple : 1;      
+    
+    ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD, 
+                                  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
+    
+    do {
+        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
+    } while ((byte & IDE_REGISTER_STATUS_BSY) || 
+             (!(byte & IDE_REGISTER_STATUS_DRDY)));
+
+    for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
+    {
+        unsigned32 reg = (1 << i);
+        if (areq->regs.to_write & reg)
+            ide_controller_write_register(ctrl_minor, i, 
+                                          areq->regs.regs[i]);
+    }
+
+    do {
+        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
+    } while (byte & IDE_REGISTER_STATUS_BSY);
+
+    ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
+    ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
+
+    if (val & IDE_REGISTER_STATUS_ERR)
+    {
+        areq->breq->status = RTEMS_UNSATISFIED;
+        areq->breq->error = RTEMS_IO_ERROR;
+        return;
+    }
+ 
+    switch(areq->type)
+    {
+        case ATA_COMMAND_TYPE_PIO_IN:
+            ide_controller_read_data_block(
+                ctrl_minor, 
+                MIN(data_bs, areq->cnt) * ATA_SECTOR_SIZE,
+                areq->breq->bufs, &areq->cbuf,
+                &areq->pos);
+              
+            areq->cnt -= MIN(data_bs, areq->cnt);
+            if (areq->cnt == 0)
+            {
+                areq->breq->status = RTEMS_SUCCESSFUL;
+            }
+            else 
+            {
+                /* 
+                 * this shouldn't happend on the initialization 
+                 * phase! 
+                 */
+                rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR); 
+            }
+            break;
+                
+        case ATA_COMMAND_TYPE_NON_DATA:
+            areq->breq->status = RTEMS_SUCCESSFUL;
+            areq->breq->error = val1;
+            break;
+            
+        default:
+            printf("ata_queue_task: non-supported command type\n");
+            areq->breq->status = RTEMS_UNSATISFIED;
+            areq->breq->error = RTEMS_NOT_IMPLEMENTED;
+            break;          
+    }
+}
Index: c/src/libchip/ide/ata.h
===================================================================
--- c/src/libchip/ide/ata.h	(revision 5f8394736711a4297b76e8933eaf17f18b3ffafc)
+++ c/src/libchip/ide/ata.h	(revision 5f8394736711a4297b76e8933eaf17f18b3ffafc)
@@ -0,0 +1,55 @@
+/*
+ * ata.h
+ *
+ * ATA RTEMS driver header file. This file should be included from an 
+ * application.
+ *
+ * Copyright (C) 2002 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ * 
+ * $Id$
+ */
+#ifndef __ATA_H__
+#define __ATA_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <sys/ioctl.h>
+
+#include <rtems/blkdev.h>
+
+rtems_device_driver ata_initialize(
+        rtems_device_major_number major,
+        rtems_device_minor_number minor,
+        void *args);
+        
+#define ATA_DRIVER_TABLE_ENTRY \
+    {ata_initialize, GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES}
+    
+/* ATA IOCTL request codes */
+#define ATAIO_SET_MULTIPLE_MODE          _IO('A', 1)
+
+/* 
+ * ATA driver configuration parameters 
+ * FIXME: should be configured more easy...
+ */
+#define ATA_DRIVER_MESSAGE_QUEUE_SIZE    50
+#define ATA_DRIVER_TASK_PRIORITY         140
+#define ATA_DRIVER_TASK_STACK_SIZE       16*1024 
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __ATA_H__ */
+
+
+
Index: c/src/libchip/ide/ata_internal.h
===================================================================
--- c/src/libchip/ide/ata_internal.h	(revision 5f8394736711a4297b76e8933eaf17f18b3ffafc)
+++ c/src/libchip/ide/ata_internal.h	(revision 5f8394736711a4297b76e8933eaf17f18b3ffafc)
@@ -0,0 +1,328 @@
+/*
+ * ata_internal.h
+ *
+ * ATA RTEMS driver internal header file 
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Authors: Eugeny S. Mints     <Eugeny.Mints@oktet.ru>
+ *          Alexandra Kossovsky <sasha@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ * 
+ * $Id$
+ *
+ */
+#ifndef __ATA_INTERNAL_H__
+#define __ATA_INTERNAL_H__
+
+#include <rtems.h>
+#include <sys/types.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+
+#include <rtems/blkdev.h>
+#include <rtems/diskdevs.h>
+
+/*
+ * Conversion from and to little-endian byte order. (no-op on i386/i486)
+ *
+ * Naming: Ca_b_c, where a: F = from, T = to, b: LE = little-endian,
+ * BE = big-endian, c: W = word (16 bits), L = longword (32 bits)
+ */
+#if (CPU_BIG_ENDIAN == TRUE)
+#    define CF_LE_W(v) CPU_swap_u16(v)
+#    define CF_LE_L(v) CPU_swap_u32(v)
+#    define CT_LE_W(v) CPU_swap_u16(v)
+#    define CT_LE_L(v) CPU_swap_u32(v)
+#else
+#    define CF_LE_W(v) (v)
+#    define CF_LE_L(v) (v)
+#    define CT_LE_W(v) (v)
+#    define CT_LE_L(v) (v)
+#endif
+
+#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
+#define ATA_UNDEFINED_VALUE   (-1)
+
+/* Sector size for all ATA devices */
+#define ATA_SECTOR_SIZE                 512
+
+
+#define ATA_MAX_CMD_REG_OFFSET          8
+
+/* ATA modes */
+#define ATA_MODES_PIO3    0x001
+#define ATA_MODES_PIO4    0x002
+
+#define ATA_MODES_PIO     0x003
+
+#define ATA_MODES_DMA0    0x004
+#define ATA_MODES_DMA1    0x008
+#define ATA_MODES_DMA2    0x010
+
+#define ATA_MODES_UDMA0   0x020
+#define ATA_MODES_UDMA1   0x040
+#define ATA_MODES_UDMA2   0x080
+#define ATA_MODES_UDMA3   0x100
+#define ATA_MODES_UDMA4   0x200
+#define ATA_MODES_UDMA5   0x400
+
+#define ATA_MODES_UDMA    0x7e0
+#define ATA_MODES_DMA     0x7fc
+
+
+/* ATA Commands */
+
+/* Types of ATA commands */
+#define ATA_COMMAND_TYPE_NON_DATA   0
+#define ATA_COMMAND_TYPE_PIO_IN     1
+#define ATA_COMMAND_TYPE_PIO_OUT    2
+#define ATA_COMMAND_TYPE_DMA        3
+
+/* ATA commands opcodes */
+/* 
+ * Commands present in both ATA-2 and ATA-4 specs. 
+ * Some commands have two values in ATA-2, 
+ * in such case value from ATA-4 used.
+ * Some commands have slightly different names in these specifications,
+ * so names from ATA-4 are used.
+ */
+#define ATA_COMMAND_NOP                          0x00
+#define ATA_COMMAND_READ_SECTORS                 0x20
+#define ATA_COMMAND_WRITE_SECTORS                0x30
+#define ATA_COMMAND_READ_VERIFY_SECTORS          0x40
+#define ATA_COMMAND_SEEK                         0x70 /* or 0x7. */
+#define ATA_COMMAND_EXECUTE_DEVICE_DIAGNOSTIC    0x90
+#define ATA_COMMAND_INITIALIZE_DEVICE_PARAMETERS 0x91
+#define ATA_COMMAND_DOWNLOAD_MICROCODE           0x92
+#define ATA_COMMAND_READ_MULTIPLE                0xc4
+#define ATA_COMMAND_WRITE_MULTIPLE               0xc5
+#define ATA_COMMAND_SET_MULTIPLE_MODE            0xc6
+#define ATA_COMMAND_READ_DMA                     0xc8
+#define ATA_COMMAND_WRITE_DMA                    0xca
+#define ATA_COMMAND_STANDBY_IMMEDIATE            0xe0 /* or 0x94 */
+#define ATA_COMMAND_IDLE_IMMEDIATE               0xe1 /* or 0x95 */
+#define ATA_COMMAND_STANDBY                      0xe2 /* or 0x96 */
+#define ATA_COMMAND_IDLE                         0xe3 /* or 0x97 */
+#define ATA_COMMAND_READ_BUFFER                  0xe4
+#define ATA_COMMAND_CHECK_POWER_MODE             0xe5 /* or 0x98 in ATA-2 */
+#define ATA_COMMAND_SLEEP                        0xe6 /* or 0x99 */
+#define ATA_COMMAND_WRITE_BUFFER                 0xe8
+#define ATA_COMMAND_IDENTIFY_DEVICE              0xec
+#define ATA_COMMAND_SET_FEATURES                 0xef
+
+/* Commands present in both ATA-2 and ATA-4 specs: removable media */
+#define ATA_COMMAND_MEDIA_LOCK                   0xde
+#define ATA_COMMAND_MEDIA_UNLOCK                 0xdf
+#define ATA_COMMAND_MEDIA_EJECT                  0xed
+
+
+/* Commands present in ATA-2, but not in ATA-4 (not used) */
+#define ATA_COMMAND_RECALIBRATE                  0x10 /* or 0x1. */
+#define ATA_COMMAND_READ_SECTOR_NON_RETRY        0x21
+#define ATA_COMMAND_READ_LONG_RETRY              0x22
+#define ATA_COMMAND_READ_LONG_NON_RETRY          0x23
+#define ATA_COMMAND_WRITE_SECTOR_NON_RETRY       0x31
+#define ATA_COMMAND_WRITE_LONG_RETRY             0x32
+#define ATA_COMMAND_WRITE_LONG_NON_RETRY         0x33
+#define ATA_COMMAND_WRITE_VERIFY                 0x3c
+#define ATA_COMMAND_READ_VERIFY_SECTOR_NON_RETRY 0x41
+#define ATA_COMMAND_FORMAT_TRACK                 0x50
+#define ATA_COMMAND_READ_DMA_NON_RETRY           0xc9
+#define ATA_COMMAND_WRITE_DMA_NON_RETRY          0xcb
+#define ATA_COMMAND_ACKNOWLEGE_MEDIA_CHANGE      0xdb
+#define ATA_COMMAND_BOOT_POST_BOOT               0xdc
+#define ATA_COMMAND_BOOT_PRE_BOOT                0xdd
+#define ATA_COMMAND_WRITE_SAME                   0xe9
+
+/* Commands from ATA-4 specification: CFA feature set */
+#define ATA_COMMAND_CFA_REQUEST_EXTENDED_ERROR_CODE  0x03
+#define ATA_COMMAND_CFA_WRITE_SECTORS_WITHOUT_ERASE  0x38
+#define ATA_COMMAND_CFA_TRANSLATE_SECTOR             0x87
+#define ATA_COMMAND_CFA_ERASE_SECTORS                0xc0
+#define ATA_COMMAND_CFA_WRITE_MULTIPLE_WITHOUT_ERASE 0xcd
+
+/* Commands from ATA-4 specification: commands to use with PACKET command */
+#define ATA_COMMAND_DEVICE_RESET                 0x08
+#define ATA_COMMAND_PACKET                       0xa0
+#define ATA_COMMAND_IDENTIFY_PACKET_DEVICE       0xa1
+#define ATA_COMMAND_SERVICE                      0xa2
+
+/* Commands from ATA-4 specification: SECURITY commands */
+#define ATA_COMMAND_SECURITY_SET_PASSWORD        0xf1
+#define ATA_COMMAND_SECURITY_UNLOCK              0xf2
+#define ATA_COMMAND_SECURITY_ERASE_PREPARE       0xf3
+#define ATA_COMMAND_SECURITY_ERASE_UNIT          0xf4
+#define ATA_COMMAND_SECURITY_FREEZE_LOCK         0xf5
+#define ATA_COMMAND_SECURITY_DISABLE_PASSWORD    0xf6
+
+/* Commands from ATA-4 specification: other commands */
+#define ATA_COMMAND_SMART                        0xb0
+#define ATA_COMMAND_READ_DMA_QUEUED              0xc7
+#define ATA_COMMAND_WRITE_DMA_QUEUED             0xcc
+#define ATA_COMMAND_GET_MEDIA_STATUS             0xda
+#define ATA_COMMAND_FLUSH_CACHE                  0xe7
+#define ATA_COMMAND_READ_NATIVE_MAX_ADDRESS      0xf8
+#define ATA_COMMAND_SET_MAX_ADDRESS              0xf9
+
+#define ATA_REGISTERS_VALUE(reg)    (1 << (reg))
+
+/* ATA IDENTIFY DEVICE command words and bits */
+#define ATA_IDENT_WORD_RW_MULT                   47
+#define ATA_IDENT_WORD_CAPABILITIES              49
+#define ATA_IDENT_WORD_FIELD_VALIDITY            53
+#define ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS     54
+#define ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS     55
+#define ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS      56
+#define ATA_IDENT_WORD_MULT_SECS                 59
+#define ATA_IDENT_WORD_NUM_OF_USR_SECS0          60
+#define ATA_IDENT_WORD_NUM_OF_USR_SECS1          61
+#define ATA_IDENT_WORD_PIO_SPPRTD                64
+
+#define ATA_IDENT_BIT_VALID                      0x02
+
+/*
+ * It is OR for all ATA_REGISTERS_VALUE(reg), where reg is neccessary
+ * for setting block position
+ */
+#define ATA_REGISTERS_POSITION       0xfc
+
+#define ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE     64
+
+#define ATA_MAX_RTEMS_INT_VEC_NUMBER              255
+
+#define ATA_MAX_NAME_LENGTH                       10
+
+/* diagnostic codes */
+#define ATA_DEV0_PASSED_DEV1_PASSED_OR_NOT_PRSNT  0x01
+#define ATA_DEV0_PASSED_DEV1_FAILED               0x81
+#define ATA_DEV1_PASSED_DEV0_FAILED               0x80
+
+/*
+ * Obtain ata device parameters by controller minor number and device number
+ */
+#define ATA_DEV_INFO(controller_minor, dev) \
+    ata_ide_ctrls[controller_minor].device[dev]
+
+/* ATA RTEMS driver internal data stuctures */
+
+/* Command block registers */
+typedef struct ata_registers_s {
+    unsigned16 regs[8];  /* command block registers */
+    unsigned16 to_read;  /* mask: which ata registers should be read */
+    unsigned16 to_write; /* mask: which ata registers should be written */
+} ata_registers_t;
+
+/* ATA request */
+typedef struct ata_req_s {
+    Chain_Node        link;   /* link in requests chain */
+    char              type;   /* request type */
+    ata_registers_t   regs;   /* ATA command */
+    rtems_unsigned32  cnt;    /* Number of sectors to be exchanged */
+    rtems_unsigned32  cbuf;   /* number of current buffer from breq in use */
+    rtems_unsigned32  pos;    /* current position in 'cbuf' */
+    blkdev_request   *breq;   /* blkdev_request which corresponds to the 
+                               * ata request
+                               */
+    rtems_id          sema;   /* semaphore which is used if synchronous 
+                               * processing of the ata request is required 
+                               */
+    rtems_status_code status; /* status of ata request processing */
+    int               error;  /* device error code */
+} ata_req_t;
+
+/* call callback provided by block device request if it is defined */
+#define ATA_EXEC_CALLBACK(areq, status, error) \
+    do {\
+        if (((areq)->breq != NULL) && ((areq)->breq->req_done != NULL)) \
+            (areq)->breq->req_done((areq)->breq->done_arg, status, error); \
+    } while (0)
+
+/* ATA RTEMS driver events types */
+typedef enum ata_msg_type_s {
+    ATA_MSG_GEN_EVT = 1,     /* general event */
+    ATA_MSG_SUCCESS_EVT,     /* success event */
+    ATA_MSG_ERROR_EVT,       /* error event */
+    ATA_MSG_PROCESS_NEXT_EVT /* process next request event */
+} ata_msg_type_t;
+
+/* ATA RTEMS driver message */
+typedef struct ata_queue_msg_s {
+    ata_msg_type_t            type;       /* message type */
+    rtems_device_minor_number ctrl_minor; /* IDE controller minor number */
+    int                       error;      /* error code */
+} ata_queue_msg_t;
+
+/* macros for messages processing */
+#define ATA_FILL_MSG(msg, evt_type, ctrl, err)\
+    do {\
+        msg.type = evt_type;\
+        msg.ctrl_minor = ctrl;\
+        msg.error = err;\
+    } while (0)
+
+#define ATA_SEND_EVT(msg, type, ctrl, err)\
+    do {\
+        rtems_status_code rc;\
+        ATA_FILL_MSG(msg, type, ctrl, err);\
+        rc = rtems_message_queue_send(ata_queue_id, &msg,\
+                                      sizeof(ata_queue_msg_t));\
+        if (rc != RTEMS_SUCCESSFUL)\
+            rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);\
+    } while (0)
+
+/*
+ * Array of such structures is indexed by interrupt vecotrs and used for 
+ * mapping of IDE controllers and interrupt vectors 
+ */
+typedef struct ata_int_st_s {
+    Chain_Node                link;
+    rtems_device_minor_number ctrl_minor;
+} ata_int_st_t;
+
+/*
+ * Mapping of rtems ATA devices to the following pairs:
+ * (IDE controller number served the device, device number on the controller)
+ */
+typedef struct ata_ide_dev_s {
+    int ctrl_minor;/* minor number of IDE controller served rtems ATA device */
+    int device;    /* device number on IDE controller (0 or 1) */
+} ata_ide_dev_t;
+
+/*
+ * ATA device description
+ */
+typedef struct ata_dev_s {
+    signed8     present;     /* 1 -- present, 0 -- not present, */
+                             /* -1 -- non-initialized */
+    unsigned16  cylinders;
+    unsigned16  heads;
+    unsigned16  sectors;
+    unsigned32  lba_sectors;  /* for small disk */
+                              /* == cylinders * heads * sectors */
+
+    unsigned8   lba_avaible;  /* 0 - CHS mode, 1 - LBA mode */
+
+    unsigned8   max_multiple; /* 0 if READ/WRITE MULTIPLE is unsupported */
+    unsigned8   current_multiple;
+
+    unsigned8   modes_avaible; /* OR of values for this modes */
+    unsigned8   mode_active;
+} ata_dev_t;
+
+/*
+ * This structure describes controller state, devices configuration on the 
+ * controller and chain of ATA requests to the controller. Array of such 
+ * structures is indexed by controller minor number 
+ */
+typedef struct ata_ide_ctrl_s {
+    rtems_boolean present;   /* controller state */
+    ata_dev_t     device[2]; /* ata diveces description */
+    Chain_Control reqs;      /* requests chain */
+} ata_ide_ctrl_t;
+
+#endif /* __ATA_INTERNAL_H__ */
+
+ 
