summaryrefslogtreecommitdiffstats
path: root/cpukit
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2002-10-28 14:00:43 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2002-10-28 14:00:43 +0000
commitef142d71a50c742ee9e4e9c53052a53d8bbfffcf (patch)
tree69eb3fab240ffead981c8e458a7d20e11ceeab68 /cpukit
parent2002-10-28 Joel Sherrill <joel@OARcorp.com> (diff)
downloadrtems-ef142d71a50c742ee9e4e9c53052a53d8bbfffcf.tar.bz2
2002-10-28 Eugeny S. Mints <Eugeny.Mints@oktet.ru>
* Added ATA support. * include/rtems/blkdev.h: Added last IO status. * include/rtems/ata.h, include/rtems/ata_internal.h, include/rtems/ide_part_table.h, src/ata.c, src/ide_part_table.c: New files.
Diffstat (limited to 'cpukit')
-rw-r--r--cpukit/libblock/ChangeLog8
-rw-r--r--cpukit/libblock/include/rtems/ata.h55
-rw-r--r--cpukit/libblock/include/rtems/ata_internal.h328
-rw-r--r--cpukit/libblock/include/rtems/blkdev.h4
-rw-r--r--cpukit/libblock/include/rtems/ide_part_table.h186
-rw-r--r--cpukit/libblock/src/ata.c1319
-rw-r--r--cpukit/libblock/src/ide_part_table.c518
7 files changed, 2418 insertions, 0 deletions
diff --git a/cpukit/libblock/ChangeLog b/cpukit/libblock/ChangeLog
index 0865f89195..dff0893498 100644
--- a/cpukit/libblock/ChangeLog
+++ b/cpukit/libblock/ChangeLog
@@ -1,3 +1,11 @@
+2002-10-28 Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+
+ * Added ATA support.
+ * include/rtems/blkdev.h: Added last IO status.
+ * include/rtems/ata.h, include/rtems/ata_internal.h,
+ include/rtems/ide_part_table.h, src/ata.c, src/ide_part_table.c: New
+ files.
+
2002-10-25 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
* configure.ac: Add nostdinc to AM_INIT_AUTOMAKE.
diff --git a/cpukit/libblock/include/rtems/ata.h b/cpukit/libblock/include/rtems/ata.h
new file mode 100644
index 0000000000..d77a96a7e3
--- /dev/null
+++ b/cpukit/libblock/include/rtems/ata.h
@@ -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__ */
+
+
+
diff --git a/cpukit/libblock/include/rtems/ata_internal.h b/cpukit/libblock/include/rtems/ata_internal.h
new file mode 100644
index 0000000000..0b17703ede
--- /dev/null
+++ b/cpukit/libblock/include/rtems/ata_internal.h
@@ -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__ */
+
+ \ No newline at end of file
diff --git a/cpukit/libblock/include/rtems/blkdev.h b/cpukit/libblock/include/rtems/blkdev.h
index ca3b5ba5e2..5f3f6159ea 100644
--- a/cpukit/libblock/include/rtems/blkdev.h
+++ b/cpukit/libblock/include/rtems/blkdev.h
@@ -62,6 +62,10 @@ typedef struct blkdev_request {
blkdev_request_op req; /* Block device operation (read or write) */
blkdev_request_cb req_done; /* Callback function */
void *done_arg; /* Argument to be passed to callback function*/
+ rtems_status_code status; /* Last I/O operation completion status */
+ int error; /* If status != RTEMS_SUCCESSFUL, this field
+ * contains error code
+ */
blkdev_bnum start; /* Start block number */
rtems_unsigned32 count; /* Number of blocks to be exchanged */
rtems_unsigned32 bufnum; /* Number of buffers provided */
diff --git a/cpukit/libblock/include/rtems/ide_part_table.h b/cpukit/libblock/include/rtems/ide_part_table.h
new file mode 100644
index 0000000000..79d3f7710a
--- /dev/null
+++ b/cpukit/libblock/include/rtems/ide_part_table.h
@@ -0,0 +1,186 @@
+/*****************************************************************************
+ *
+ * ide_part_table.h
+ *
+ * The header file for library supporting "MS-DOS-style" partition table
+ *
+ *
+ * Copyright (C) 2002 OKTET Ltd., St.-Petersburg, Russia
+ *
+ * Author: Konstantin Abramenko <Konstantin.Abramenko@oktet.ru>
+ * Alexander Kukuta <Alexander.Kukuta@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 __RTEMS_IDE_PART_TABLE_H__
+#define __RTEMS_IDE_PART_TABLE_H__
+
+#include <assert.h>
+#include <chain.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <rtems.h>
+#include <rtems/blkdev.h>
+#include <rtems/libio.h>
+#include <rtems/libio_.h>
+#include <rtems/bdbuf.h>
+#include <rtems/seterr.h>
+
+/* Minor base number for all logical devices */
+#define RTEMS_IDE_SECTOR_BITS 9
+#define RTEMS_IDE_SECTOR_SIZE 512
+#define RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE 16
+#define RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER 63
+#define RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER 4
+#define RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX 16
+
+#define RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA1 0x55
+#define RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA2 0xaa
+#define RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET 0x1fe
+#define RTEMS_IDE_PARTITION_TABLE_OFFSET 0x1be
+#define RTEMS_IDE_PARTITION_BOOTABLE_OFFSET 0
+#define RTEMS_IDE_PARTITION_SYS_TYPE_OFFSET 4
+#define RTEMS_IDE_PARTITION_START_OFFSET 8
+#define RTEMS_IDE_PARTITION_SIZE_OFFSET 12
+
+/*
+ * Conversion from and to little-endian byte order. (no-op on i386/i486)
+ */
+
+#if (CPU_BIG_ENDIAN == TRUE)
+# define LE_TO_CPU_U16(v) CPU_swap_u16(v)
+# define LE_TO_CPU_U32(v) CPU_swap_u32(v)
+# define CPU_TO_LE_U16(v) CPU_swap_u16(v)
+# define CPU_TO_LE_U32(v) CPU_swap_u32(v)
+#else
+# define LE_TO_CPU_U16(v) (v)
+# define LE_TO_CPU_U32(v) (v)
+# define CPU_TO_LE_U16(v) (v)
+# define CPU_TO_LE_U32(v) (v)
+#endif
+
+
+/*
+ * sector_data_t --
+ * corresponds to the sector on the device
+ */
+typedef struct sector_data_s
+{
+ unsigned32 sector_num; /* sector number on the device */
+ unsigned8 data[0]; /* raw sector data */
+} sector_data_t;
+
+
+/*
+ * Enum partition types
+ */
+enum {
+ EMPTY_PARTITION = 0,
+ EXTENDED_PARTITION = 5,
+ DM6_PARTITION = 0x54,
+ EZD_PARTITION = 0x55,
+ DM6_AUX1PARTITION = 0x51,
+ DM6_AUX3PARTITION = 0x53,
+ LINUX_SWAP = 0x82,
+ LINUX_NATIVE = 0x83,
+ LINUX_EXTENDED = 0x85
+};
+
+
+/* Forward declaration */
+struct disk_desc_s;
+
+/*
+ * part_desc_t --
+ * contains all neccessary information about partition
+ */
+typedef struct part_desc_s {
+ unsigned8 bootable; /* is the partition active */
+ unsigned8 sys_type; /* type of partition */
+ unsigned8 log_id; /* logical number of partition */
+ unsigned32 start; /* first partition sector, in absolute numeration */
+ unsigned32 size; /* size in sectors */
+ unsigned32 end; /* last partition sector, end = start + size - 1 */
+ struct disk_desc_s *disk_desc; /* descriptor of disk, partition contains in */
+ struct part_desc_s *ext_part; /* extended partition containing this one */
+
+ /* partitions, containing in this one */
+ struct part_desc_s *sub_part[RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER];
+} part_desc_t;
+
+
+
+typedef struct disk_desc_s {
+ dev_t dev; /* device number */
+
+ /* device name in /dev filesystem */
+ unsigned8 dev_name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX];
+
+ unsigned32 sector_size; /* size of sector */
+ unsigned32 sector_bits; /* the base-2 logarithm of sector_size */
+ unsigned32 lba_size; /* total amount of sectors in lba address mode */
+ int last_log_id; /* used for logical disks enumerating */
+
+ /* primary partition descriptors */
+ part_desc_t *partitions[RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER];
+} disk_desc_t;
+
+
+/*
+ * rtems_ide_part_table_free --
+ * frees disk descriptor structure
+ *
+ * PARAMETERS:
+ * disk_desc - disc descriptor structure to free
+ *
+ * RETURNS:
+ * N/A
+ */
+void
+rtems_ide_part_table_free(disk_desc_t *disk_desc);
+
+
+/*
+ * rtems_ide_part_table_get --
+ * reads partition table structure from the device
+ * and creates disk description structure
+ *
+ * PARAMETERS:
+ * dev_name - path to physical device in /dev filesystem
+ * disk_desc - returned disc description structure
+ *
+ * RETURNS:
+ * RTEMS_SUCCESSFUL if success, or -1 and corresponding errno else
+ */
+rtems_status_code
+rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc);
+
+
+/*
+ * rtems_ide_part_table_initialize --
+ * initializes logical devices on the physical IDE drive
+ *
+ * PARAMETERS:
+ * dev_name - path to physical device in /dev filesystem
+ *
+ * RETURNS:
+ * RTEMS_SUCCESSFUL if success, or -1 and corresponding errno else
+ */
+rtems_status_code
+rtems_ide_part_table_initialize(char *dev_name);
+
+
+#endif /* __RTEMS_IDE_PART_TABLE_H__ */
diff --git a/cpukit/libblock/src/ata.c b/cpukit/libblock/src/ata.c
new file mode 100644
index 0000000000..3087d62141
--- /dev/null
+++ b/cpukit/libblock/src/ata.c
@@ -0,0 +1,1319 @@
+/*
+ * 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 <rtems/diskdevs.h>
+#include <rtems/blkdev.h>
+#include <libchip/ide_ctrl_io.h>
+#include <libchip/ide_ctrl_cfg.h>
+#include <rtems/ata_internal.h>
+#include <rtems/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_PREEMPT_MASK, RTEMS_NO_PREEMPT, &(key)); \
+ } while (0)
+
+#define ENABLE_PREEMPTION(key) \
+ do { \
+ rtems_mode temp; \
+ rtems_task_mode(RTEMS_PREEMPT_MASK, (key), &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;
+
+#ifndef ATA_DEV_IS_FLASH_DISK
+ if ((CF_LE_W(buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
+ ATA_IDENT_BIT_VALID) == 0)
+ continue;
+#endif
+ 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;
+
+#ifdef ATA_DEV_IS_FLASH_DISK
+ ATA_DEV_INFO(ctrl_minor, dev).mode_active = ATA_MODES_PIO3;
+#endif
+ /*
+ * 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;
+ }
+}
diff --git a/cpukit/libblock/src/ide_part_table.c b/cpukit/libblock/src/ide_part_table.c
new file mode 100644
index 0000000000..ec5460ff4c
--- /dev/null
+++ b/cpukit/libblock/src/ide_part_table.c
@@ -0,0 +1,518 @@
+/*****************************************************************************
+ *
+ * ide_part_table.c
+ *
+ * The implementation of library supporting "MS-DOS-style" partition table
+ *
+ *
+ * Copyright (C) 2002 OKTET Ltd., St.-Petersburg, Russia
+ *
+ * Author: Konstantin Abramenko <Konstantin.Abramenko@oktet.ru>
+ * Alexander Kukuta <Alexander.Kukuta@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 <rtems/ide_part_table.h>
+
+
+/*
+ * get_sector --
+ * gets sector from the disk
+ *
+ * PARAMETERS:
+ * dev - device number
+ * sector_num - number of sector to read
+ * sector - returned pointer to pointer to allocated
+ * sector_data_t structure
+ *
+ * RETURNS:
+ * RTEMS_SUCCESSFUL, if success;
+ * RTEMS_NO_MEMORY, if canot allocate memory for sector data;
+ * other error codes returned by rtems_bdbuf_read().
+ *
+ * NOTES:
+ * get_sector() operates with device via bdbuf library,
+ * and does not support devices with sector size other than 512 bytes
+ */
+static rtems_status_code
+get_sector(dev_t dev, unsigned32 sector_num, sector_data_t **sector)
+{
+ sector_data_t *s;
+ bdbuf_buffer *buf;
+ rtems_status_code rc;
+
+ if (sector == NULL)
+ {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ s = (sector_data_t *) malloc(sizeof(sector_data_t) + RTEMS_IDE_SECTOR_SIZE);
+ if (s == NULL)
+ {
+ return RTEMS_NO_MEMORY;
+ }
+
+ rc = rtems_bdbuf_read(dev, sector_num, &buf);
+ if (rc != RTEMS_SUCCESSFUL)
+ {
+ free(s);
+ return rc;
+ }
+
+ memcpy(s->data, buf->buffer, RTEMS_IDE_SECTOR_SIZE);
+ s->sector_num = sector_num;
+
+ *sector = s;
+
+ rtems_bdbuf_release(buf);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ * msdos_signature_check --
+ * checks if the partition table sector has msdos signature
+ *
+ * PARAMETERS:
+ * sector - sector to check
+ *
+ * RETURNS:
+ * TRUE if sector has msdos signature, FALSE otherwise
+ */
+static rtems_boolean
+msdos_signature_check (sector_data_t *sector)
+{
+ unsigned8 *p = sector->data + RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET;
+
+ return ((p[0] == RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA1) &&
+ (p[1] == RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA2));
+}
+
+
+/*
+ * is_extended --
+ * checks if the partition type is extended
+ *
+ * PARAMETERS:
+ * type - type of partition to check
+ *
+ * RETURNS:
+ * TRUE if partition type is extended, FALSE otherwise
+ */
+static rtems_boolean
+is_extended(unsigned8 type)
+{
+ return ((type == EXTENDED_PARTITION) || (type == LINUX_EXTENDED));
+}
+
+
+/*
+ * data_to_part_desc --
+ * parses raw partition table sector data
+ * to partition description structure
+ *
+ * PARAMETERS:
+ * data - raw partition table sector data
+ * new_part_desc - pointer to returned partition description structure
+ *
+ * RETURNS:
+ * RTEMS_SUCCESSFUL, if success;
+ * RTEMS_NO_MEMOTY, if cannot allocate memory for part_desc_t strucure;
+ * RTEMS_INTERNAL_ERROR, if other error occurs.
+ */
+static rtems_status_code
+data_to_part_desc(unsigned8 *data, part_desc_t **new_part_desc)
+{
+ part_desc_t *part_desc;
+ unsigned32 temp;
+
+ if (new_part_desc == NULL)
+ {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ *new_part_desc = NULL;
+
+ if ((part_desc = calloc(1, sizeof(part_desc_t))) == NULL)
+ {
+ return RTEMS_NO_MEMORY;
+ }
+
+ part_desc->bootable = *(data + RTEMS_IDE_PARTITION_BOOTABLE_OFFSET);
+ part_desc->sys_type = *(data + RTEMS_IDE_PARTITION_SYS_TYPE_OFFSET);
+
+ /* read the offset start position and partition size in sectors */
+
+ /* due to incorrect data alignment one have to align data first */
+ memcpy(&temp, data + RTEMS_IDE_PARTITION_START_OFFSET, sizeof(unsigned32));
+ part_desc->start = LE_TO_CPU_U32(temp);
+
+ memcpy(&temp, data + RTEMS_IDE_PARTITION_SIZE_OFFSET, sizeof(unsigned32));
+ part_desc->size = LE_TO_CPU_U32(temp);
+
+ if ((part_desc->sys_type == EMPTY_PARTITION) ||
+ ((part_desc->size == 0) && (!is_extended(part_desc->sys_type))))
+ {
+ /* empty partition */
+ free(part_desc);
+ return RTEMS_SUCCESSFUL;
+ }
+
+ *new_part_desc = part_desc;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ * read_extended_partition --
+ * recursively reads extended partition sector from the device
+ * and constructs the partition table tree
+ *
+ * PARAMETERS:
+ * start - start sector of primary extended partition, used for
+ * calculation of absolute partition sector address
+ * ext_part - description of extended partition to process
+ *
+ * RETURNS:
+ * RTEMS_SUCCESSFUL if success,
+ * RTEMS_NO_MEMOTY if cannot allocate memory for part_desc_t strucure,
+ * RTEMS_INTERNAL_ERROR if other error occurs.
+ */
+static rtems_status_code
+read_extended_partition(unsigned32 start, part_desc_t *ext_part)
+{
+ int i;
+ dev_t dev;
+ sector_data_t *sector;
+ unsigned32 here;
+ unsigned8 *data;
+ part_desc_t *new_part_desc;
+ rtems_status_code rc;
+
+ if ((ext_part == NULL) || (ext_part->disk_desc == NULL))
+ {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ dev = ext_part->disk_desc->dev;
+
+ /* get start sector of current extended partition */
+ here = ext_part->start;
+
+ /* get first extended partition sector */
+
+ rc = get_sector(dev, here, &sector);
+ if (rc != RTEMS_SUCCESSFUL)
+ {
+ return rc;
+ }
+
+ if (!msdos_signature_check(sector))
+ {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* read and process up to 4 logical partition descriptors */
+
+ data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
+
+ for (i = 0; i < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; i++)
+ {
+ /* if data_to_part_desc fails skip this partition
+ * and parse the next one
+ */
+ rc = data_to_part_desc(data, &new_part_desc);
+ if (rc != RTEMS_SUCCESSFUL)
+ {
+ free(sector);
+ return rc;
+ }
+
+ if (new_part_desc == NULL)
+ {
+ data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
+ continue;
+ }
+
+ ext_part->sub_part[i] = new_part_desc;
+ new_part_desc->ext_part = ext_part;
+ new_part_desc->disk_desc = ext_part->disk_desc;
+
+ if (is_extended(new_part_desc->sys_type))
+ {
+ new_part_desc->log_id = EMPTY_PARTITION;
+ new_part_desc->start += start;
+ read_extended_partition(start, new_part_desc);
+ }
+ else
+ {
+ disk_desc_t *disk_desc = new_part_desc->disk_desc;
+ disk_desc->partitions[disk_desc->last_log_id] = new_part_desc;
+ new_part_desc->log_id = ++disk_desc->last_log_id;
+ new_part_desc->start += here;
+ new_part_desc->end = new_part_desc->start + new_part_desc->size - 1;
+ }
+ data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
+ }
+
+ free(sector);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ * read_mbr --
+ * reads Master Boot Record (sector 0) of physical device and
+ * constructs disk description structure
+ *
+ * PARAMETERS:
+ * disk_desc - returned disc description structure
+ *
+ * RETURNS:
+ * RTEMS_SUCCESSFUL if success,
+ * RTEMS_INTERNAL_ERROR otherwise
+ */
+static rtems_status_code
+read_mbr(disk_desc_t *disk_desc)
+{
+ int part_num;
+ sector_data_t *sector;
+ part_desc_t *part_desc;
+ unsigned8 *data;
+ rtems_status_code rc;
+ dev_t dev = disk_desc->dev;
+
+ /* get MBR sector */
+ rc = get_sector(dev, 0, &sector);
+ if (rc != RTEMS_SUCCESSFUL)
+ {
+ return rc;
+ }
+
+ /* check if the partition table structure is MS-DOS style */
+ if (!msdos_signature_check(sector))
+ {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ /* read and process 4 primary partition descriptors */
+
+ data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
+
+ for (part_num = 0;
+ part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
+ part_num++)
+ {
+ rc = data_to_part_desc(data, &part_desc);
+ if (rc != RTEMS_SUCCESSFUL)
+ {
+ free(sector);
+ return rc;
+ }
+
+ if (part_desc != NULL)
+ {
+ part_desc->log_id = part_num + 1;
+ part_desc->disk_desc = disk_desc;
+ part_desc->end = part_desc->start + part_desc->size - 1;
+ disk_desc->partitions[part_num] = part_desc;
+ }
+ else
+ {
+ disk_desc->partitions[part_num] = NULL;
+ }
+
+ data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
+ }
+
+ free(sector);
+
+ disk_desc->last_log_id = RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
+
+ /* There cannot be more than one extended partition,
+ but we are to process each primary partition */
+ for (part_num = 0;
+ part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
+ part_num++)
+ {
+ if (is_extended(disk_desc->partitions[part_num]->sys_type))
+ {
+ read_extended_partition(disk_desc->partitions[part_num]->start,
+ disk_desc->partitions[part_num]);
+ }
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ * partition free --
+ * frees partition description structure
+ *
+ * PARAMETERS:
+ * part_desc - returned disc description structure
+ *
+ * RETURNS:
+ * N/A
+ */
+static void
+partition_free(part_desc_t *part_desc)
+{
+ int part_num;
+
+ if (part_desc == NULL)
+ return;
+
+ if (is_extended(part_desc->sys_type))
+ {
+ for (part_num = 0;
+ part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
+ part_num++)
+ {
+ partition_free(part_desc->sub_part[part_num]);
+ }
+ }
+
+ free(part_desc);
+}
+
+
+/*
+ * rtems_ide_part_table_free - frees disk descriptor structure
+ *
+ * PARAMETERS:
+ * disk_desc - disc descriptor structure to free
+ *
+ * RETURNS:
+ * N/A
+ */
+void
+rtems_ide_part_table_free(disk_desc_t *disk_desc)
+{
+ int part_num;
+
+ for (part_num = 0; part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; part_num++)
+ {
+ partition_free(disk_desc->partitions[part_num]);
+ }
+
+ free(disk_desc);
+}
+
+
+/*
+ * rtems_ide_part_table_get - reads partition table structure from the device
+ * and creates disk description structure
+ *
+ * PARAMETERS:
+ * dev_name - path to physical device in /dev filesystem
+ * disk_desc - returned disc description structure
+ *
+ * RETURNS:
+ * RTEMS_SUCCESSFUL if success,
+ * RTEMS_INTERNAL_ERROR otherwise
+ */
+rtems_status_code
+rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc)
+{
+ struct stat dev_stat;
+ rtems_status_code rc;
+
+ rc = stat(dev_name, &dev_stat);
+ if (rc != RTEMS_SUCCESSFUL)
+ {
+ return RTEMS_INTERNAL_ERROR;
+ }
+
+ strncpy (disk_desc->dev_name, dev_name, 15);
+ disk_desc->dev = dev_stat.st_dev;
+ disk_desc->sector_size = (dev_stat.st_blksize) ? dev_stat.st_blksize :
+ RTEMS_IDE_SECTOR_SIZE;
+
+ rc = read_mbr(disk_desc);
+
+ return rc;
+}
+
+
+/*
+ * rtems_ide_part_table_initialize - initializes logical devices
+ * on the physical IDE drive
+ *
+ * PARAMETERS:
+ * dev_name - path to physical device in /dev filesystem
+ *
+ * RETURNS:
+ * RTEMS_SUCCESSFUL if success,
+ * RTEMS_NO_MEMOTY if cannot have not enough memory,
+ * RTEMS_INTERNAL_ERROR if other error occurs.
+ */
+rtems_status_code
+rtems_ide_part_table_initialize(char *dev_name)
+{
+ int part_num;
+ dev_t dev;
+ disk_desc_t *disk_desc;
+ rtems_device_major_number major;
+ rtems_device_minor_number minor;
+ rtems_status_code rc;
+ part_desc_t *part_desc;
+
+ /* logical device name /dev/hdxyy */
+ char name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX];
+
+ disk_desc = (disk_desc_t *) calloc(1, sizeof(disk_desc_t));
+ if (disk_desc == NULL)
+ {
+ return RTEMS_NO_MEMORY;
+ }
+
+ /* get partition table */
+ rc = rtems_ide_part_table_get(dev_name, disk_desc);
+ if (rc != RTEMS_SUCCESSFUL)
+ {
+ return rc;
+ }
+
+ /* To avoid device numbers conflicts we have to use for logic disk the same
+ * device major number as ATA device has, and minor number that equals to
+ * sum of logic disk partition number and the minor number of physical disk
+ */
+
+ rtems_filesystem_split_dev_t (disk_desc->dev, major, minor);
+
+ /* create logical disks on the physical one */
+ for (part_num = 0; part_num < disk_desc->last_log_id; part_num++)
+ {
+ sprintf(name, "%s%d", dev_name, part_num + 1);
+ dev = rtems_filesystem_make_dev_t(major, ++minor);
+
+ part_desc = disk_desc->partitions[part_num];
+ if (part_desc == NULL)
+ {
+ continue;
+ }
+
+ rc = rtems_disk_create_log(dev, disk_desc->dev, part_desc->start,
+ part_desc->size, name);
+ if (rc != RTEMS_SUCCESSFUL)
+ {
+ printf("Cannot create device %s, error code %d\n", name, rc);
+ continue;
+ }
+ }
+
+ rtems_ide_part_table_free(disk_desc);
+
+ return RTEMS_SUCCESSFUL;
+}