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.
This commit is contained in:
Joel Sherrill
2002-10-28 14:00:43 +00:00
parent 42b7ce27ce
commit ef142d71a5
7 changed files with 2418 additions and 0 deletions

View File

@@ -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.

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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 */

View File

@@ -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__ */

1319
cpukit/libblock/src/ata.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}