Changeset 3899a537 in rtems for cpukit/libblock


Ignore:
Timestamp:
Jul 29, 2008, 2:21:15 AM (12 years ago)
Author:
Chris Johns <chrisj@…>
Branches:
4.10, 4.11, 4.9, master
Children:
c4bd98c
Parents:
1b39f18
Message:

2008-07-29 Chris Johns <chrisj@…>

  • libblock/Makefile.am: Removed src/show_bdbuf.c.
  • libblock/src/show_bdbuf.c: Removed.
  • libblock/include/rtems/bdbuf.h, cpukit/libblock/src/bdbuf.c: Rewritten the bdbuf code. Remove pre-emption disable, score access, fixed many bugs and increased performance.
  • libblock/include/rtems/blkdev.h: Added RTEMS_BLKDEV_CAPABILITIES block device request. Cleaned up comments. Added block and user fields to the sg buffer request. Move to rtems_* namespace.
  • libblock/include/rtems/diskdevs.h, cpukit/libblock/src/diskdevs.c: Move to rtems_* namespace. Add a capabilities field for drivers. Change rtems_disk_lookup to rtems_disk_obtain to match the release call. You do not lookup and release a disk, you obtain and release a disk.
  • libblock/include/rtems/ide_part_table.h, libblock/include/rtems/ramdisk.h, libblock/src/ide_part_table.c: Move to rtems_* namespace.
  • libblock/include/rtems/nvdisk.h: Formatting change.
  • libblock/src/blkdev.c: Move to rtems_* namespace. Change rtems_disk_lookup to rtems_disk_obtain
  • libblock/src/flashdisk.c: Move to rtems_* namespace. Use the new support for the block number in the scatter/grather request struct. This allows non-continuous buffer requests for those drivers that can support increasing performance.
  • libblock/src/nvdisk.c: Move to rtems_* namespace. Removed warnings. Added better error checking. Fixed some comments.
  • libblock/src/ramdisk.c: Move to rtems_* namespace. Added some trace functions to help debugging upper layers. Use the new support for the block number in the scatter/grather request struct. This allows non-continuous buffer requests for those drivers that can support increasing performance.
  • libfs/src/dosfs/fat.c, libfs/src/dosfs/fat.h: Use new chains API. Removed temporary hack and changed set_errno_and_return_minus_one to rtems_set_errno_and_return_minus_one. Move fat_buf_access from header and stopped it being inlined. Updated to libblock changes.
  • libfs/src/dosfs/fat_fat_operations.c, libfs/src/dosfs/fat_file.c, libfs/src/dosfs/msdos_create.c, libfs/src/dosfs/msdos_dir.c, libfs/src/dosfs/msdos_eval.c, libfs/src/dosfs/msdos_file.c, libfs/src/dosfs/msdos_format.c, libfs/src/dosfs/msdos_free.c, libfs/src/dosfs/msdos_initsupp.c, libfs/src/dosfs/msdos_misc.c, libfs/src/dosfs/msdos_mknod.c: Use new chains API. Removed temporary hack and changed set_errno_and_return_minus_one to rtems_set_errno_and_return_minus_one. Updated to libblock changes.
  • libmisc/Makefile.am: Add new ls and rm command files.
  • libmisc/shell/cmp-ls.c, libmisc/shell/extern-ls.h, libmisc/shell/filemode.c, libmisc/shell/print-ls.c, libmisc/shell/pwcache.c, libmisc/shell/utils-ls.c, libmisc/shell/vis.c, shell/vis.h: New.
  • libmisc/shell/extern-cp.h, libmisc/shell/main_cp.c, libmisc/shell/utils-cp.c: Fixed the usage call bug.
  • libmisc/shell/main_blksync.c: Updated to the new block IO ioctl command.
  • libmisc/shell/main_ls.c, libmisc/shell/main_rm.c: Updated to BSD commands with more features.
  • score/src/coremutex.c: Fix the strick order mutex code.
  • libmisc/shell/shell.c: Change shell tasks mode to be timeslice and no ASR.
  • sapi/include/confdefs.h: Change ata_driver_task_priority to rtems_ata_driver_task_priority. Add the new BD buf cache parameters with defaults.
  • score/src/interr.c: Do not return if the CPU halt call returns.
Location:
cpukit/libblock
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libblock/Makefile.am

    r1b39f18 r3899a537  
    99noinst_LIBRARIES = libblock.a
    1010libblock_a_SOURCES = src/bdbuf.c src/blkdev.c src/diskdevs.c src/flashdisk.c \
    11     src/ramdisk.c src/ide_part_table.c src/show_bdbuf.c src/nvdisk.c \
     11    src/ramdisk.c src/ide_part_table.c src/nvdisk.c \
    1212    src/nvdisk-sram.c \
    1313    include/rtems/bdbuf.h include/rtems/blkdev.h \
  • cpukit/libblock/include/rtems/bdbuf.h

    r1b39f18 r3899a537  
    2626#include "rtems/diskdevs.h"
    2727
    28 
    29 /*
    30  * To manage buffers we using Buffer Descriptors.
    31  * To speed-up buffer lookup descriptors are organized in AVL-Tree.
    32  * The fields 'dev' and 'block' are search key.
    33  */
    34 
    35 /* Buffer descriptors
    36  * Descriptors organized in AVL-tree to speedup buffer lookup.
    37  * dev and block fields are search key in AVL-tree.
    38  * Modified buffers, free buffers and used buffers linked in 'mod', 'free' and
    39  * 'lru' chains appropriately.
    40  */
    41 
    42 typedef struct bdbuf_buffer {
    43     Chain_Node link; /* Link in the lru, mod or free chains */
    44 
    45     struct bdbuf_avl_node {
    46         signed char cache;           /* Cache */
    47 
    48             struct bdbuf_buffer* left;  /* Left Child */
    49             struct bdbuf_buffer* right; /* Right Child */
    50 
    51         signed char bal;             /* The balance of the sub-tree */
    52     } avl;
    53 
    54     dev_t       dev;     /* device number */
    55     blkdev_bnum block;   /* block number on the device */
    56 
    57     unsigned char    *buffer;  /* Pointer to the buffer memory area */
    58     rtems_status_code status; /* Last I/O operation completion status */
    59     int         error;   /* If status != RTEMS_SUCCESSFUL, this field contains
    60                             errno value which can be used by user later */
    61     boolean     modified:1;    /* =1 if buffer was modified */
    62     boolean     in_progress:1; /* =1 if exchange with disk is in progress;
    63                                   need to wait on semaphore */
    64     boolean     actual:1;      /* Buffer contains actual data */
    65     int         use_count; /* Usage counter; incremented when somebody use
    66                               this buffer; decremented when buffer released
    67                               without modification or when buffer is flushed
    68                               by swapout task */
    69 
    70     rtems_bdpool_id pool;  /* Identifier of buffer pool to which this buffer
    71                               belongs */
    72     CORE_mutex_Control transfer_sema;
    73                            /* Transfer operation semaphore */
    74 } bdbuf_buffer;
    75 
    76 
    77 /*
    78  * the following data structures are internal to the bdbuf layer,
    79  * but it is convenient to have them visible from the outside for inspection
    80  */
    81 /*
    82  * The groups of the blocks with the same size are collected in the
    83  * bd_pool. Note that a several of the buffer's groups with the
    84  * same size can exists.
    85  */
    86 typedef struct bdbuf_pool
     28/**
     29 * State of a buffer in the cache.
     30 */
     31typedef enum
    8732{
    88     bdbuf_buffer *tree;         /* Buffer descriptor lookup AVL tree root */
    89 
    90     Chain_Control free;         /* Free buffers list */
    91     Chain_Control lru;          /* Last recently used list */
    92 
    93     int           blksize;      /* The size of the blocks (in bytes) */
    94     int           nblks;        /* Number of blocks in this pool */
    95     rtems_id      bufget_sema;  /* Buffer obtain counting semaphore */
    96     void         *mallocd_bufs; /* Pointer to the malloc'd buffer memory,
    97                                    or NULL, if buffer memory provided in
    98                                    buffer configuration */
    99     bdbuf_buffer *bdbufs;       /* Pointer to table of buffer descriptors
    100                                    allocated for this buffer pool. */
    101 } bdbuf_pool;
    102 
    103 /* Buffering layer context definition */
    104 struct bdbuf_context {
    105     bdbuf_pool    *pool;         /* Table of buffer pools */
    106     int            npools;       /* Number of entries in pool table */
    107 
    108     Chain_Control  mod;          /* Modified buffers list */
    109     rtems_id       flush_sema;   /* Buffer flush semaphore; counting
    110                                     semaphore; incremented when buffer
    111                                     flushed to the disk; decremented when
    112                                     buffer modified */
    113     rtems_id       swapout_task; /* Swapout task ID */
    114 };
    115   /*
    116    * the context of the buffering layer, visible for inspection
    117    */
    118 extern struct bdbuf_context rtems_bdbuf_ctx;
    119 
    120 /* bdbuf_config structure describes block configuration (size,
    121  * amount, memory location) for buffering layer
     33  RTEMS_BDBUF_STATE_EMPTY = 0,            /* Not in use. */
     34  RTEMS_BDBUF_STATE_READ_AHEAD = 1,       /* Holds read ahead data only */
     35  RTEMS_BDBUF_STATE_CACHED = 2,           /* In the cache and available */
     36  RTEMS_BDBUF_STATE_ACCESS = 3,           /* The user has the buffer */
     37  RTEMS_BDBUF_STATE_MODIFIED = 4,         /* In the cache but modified */
     38  RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5,  /* With the user but modified */
     39  RTEMS_BDBUF_STATE_SYNC = 6,             /* Requested to be sync'ed */
     40  RTEMS_BDBUF_STATE_TRANSFER = 7          /* Being transferred to or from disk */
     41} rtems_bdbuf_buf_state;
     42
     43/**
     44 * To manage buffers we using buffer descriptors (BD). A BD holds a buffer plus
     45 * a range of other information related to managing the buffer in the cache. To
     46 * speed-up buffer lookup descriptors are organized in AVL-Tree.  The fields
     47 * 'dev' and 'block' are search keys.
     48 */
     49typedef struct rtems_bdbuf_buffer
     50{
     51  rtems_chain_node link;       /* Link in the BD onto a number of lists. */
     52
     53  struct rtems_bdbuf_avl_node
     54  {
     55    signed char                cache;  /* Cache */
     56    struct rtems_bdbuf_buffer* left;   /* Left Child */
     57    struct rtems_bdbuf_buffer* right;  /* Right Child */
     58    signed char                bal;    /* The balance of the sub-tree */
     59  } avl;
     60
     61  dev_t             dev;        /* device number */
     62  rtems_blkdev_bnum block;      /* block number on the device */
     63
     64  unsigned char*    buffer;     /* Pointer to the buffer memory area */
     65  int               error;      /* If not 0 indicate an error value (errno)
     66                                 * which can be used by user later */
     67
     68  volatile rtems_bdbuf_buf_state state;  /* State of the buffer. */
     69
     70  volatile uint32_t waiters;    /* The number of threads waiting on this
     71                                 * buffer. */
     72  rtems_bdpool_id pool;         /* Identifier of buffer pool to which this buffer
     73                                    belongs */
     74
     75  volatile uint32_t hold_timer; /* Timer to indicate how long a buffer
     76                                 * has been held in the cache modified. */
     77} rtems_bdbuf_buffer;
     78
     79/**
     80 * The groups of the blocks with the same size are collected in a pool. Note
     81 * that a several of the buffer's groups with the same size can exists.
     82 */
     83typedef struct rtems_bdbuf_pool
     84{
     85  int                 blksize;           /* The size of the blocks (in bytes) */
     86  int                 nblks;             /* Number of blocks in this pool */
     87
     88  uint32_t            flags;             /* Configuration flags */
     89
     90  rtems_id            lock;              /* The pool lock. Lock this data and
     91                                          * all BDs. */
     92  rtems_id            sync_lock;         /* Sync calls lock writes. */
     93  boolean             sync_active;       /* True if a sync is active. */
     94  rtems_id            sync_requester;    /* The sync requester. */
     95  dev_t               sync_device;       /* The device to sync */
     96
     97  rtems_bdbuf_buffer* tree;             /* Buffer descriptor lookup AVL tree
     98                                         * root */
     99  rtems_chain_control ready;            /* Free buffers list (or read-ahead) */
     100  rtems_chain_control lru;              /* Last recently used list */
     101  rtems_chain_control modified;         /* Modified buffers list */
     102  rtems_chain_control sync;             /* Buffers to sync list */
     103
     104  rtems_id            access;           /* Obtain if waiting for a buffer in the
     105                                         * ACCESS state. */
     106  volatile uint32_t   access_waiters;   /* Count of access blockers. */
     107  rtems_id            transfer;         /* Obtain if waiting for a buffer in the
     108                                         * TRANSFER state. */
     109  volatile uint32_t   transfer_waiters; /* Count of transfer blockers. */
     110  rtems_id            waiting;          /* Obtain if waiting for a buffer and the
     111                                         * none are available. */
     112  volatile uint32_t   wait_waiters;     /* Count of waiting blockers. */
     113
     114  rtems_bdbuf_buffer* bds;              /* Pointer to table of buffer descriptors
     115                                         * allocated for this buffer pool. */
     116  void*               buffers;          /* The buffer's memory. */
     117} rtems_bdbuf_pool;
     118
     119/**
     120 * Configuration structure describes block configuration (size, amount, memory
     121 * location) for buffering layer pool.
     122 */
     123typedef struct rtems_bdbuf_pool_config {
     124  int            size;      /* Size of block */
     125  int            num;       /* Number of blocks of appropriate size */
     126  unsigned char* mem_area;  /* Pointer to the blocks location or NULL, in this
     127                             * case memory for blocks will be allocated by
     128                             * Buffering Layer with the help of RTEMS partition
     129                             * manager */
     130} rtems_bdbuf_pool_config;
     131
     132/**
     133 * External references provided by the user for each pool in the system.
     134 */
     135extern rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[];
     136extern int                     rtems_bdbuf_pool_configuration_size;
     137
     138/**
     139 * Buffering configuration definition. See confdefs.h for support on using this
     140 * structure.
    122141 */
    123142typedef struct rtems_bdbuf_config {
    124     int      size;      /* Size of block */
    125     int      num;       /* Number of blocks of appropriate size */
    126     unsigned char  *mem_area;
    127                         /* Pointer to the blocks location or NULL, in this
    128                            case memory for blocks will be allocated by
    129                            Buffering Layer with the help of RTEMS partition
    130                            manager */
     143  int                 max_read_ahead_blocks; /*<< Number of blocks to read ahead. */
     144  int                 max_write_blocks;      /*<< Number of blocks to write at once. */
     145  rtems_task_priority swapout_priority;      /*<< Priority of the swap out task. */
     146  uint32_t            swapout_period;        /*<< Period swapout checks buf timers. */
     147  uint32_t            swap_block_hold;       /*<< Period a buffer is held. */
    131148} rtems_bdbuf_config;
    132149
    133 extern rtems_bdbuf_config rtems_bdbuf_configuration[];
    134 extern int rtems_bdbuf_configuration_size;
    135 
    136 #define SWAPOUT_TASK_DEFAULT_PRIORITY 15
    137 extern rtems_task_priority swapout_task_priority;
     150/**
     151 * External referernce to the configuration. The configuration is provided by
     152 * the user.
     153 */
     154extern rtems_bdbuf_config rtems_bdbuf_configuration;
     155
     156/**
     157 * The max_read_ahead_blocks value is altered if there are fewer buffers
     158 * than this defined max. This stops thrashing in the cache.
     159 */
     160#define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT    32
     161#define RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT         16
     162#define RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT    15
     163#define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250  /* milli-seconds */
     164#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT  1000 /* milli-seconds */
    138165
    139166/* rtems_bdbuf_init --
     
    144171 *     free elements lists.
    145172 *
    146  * PARAMETERS:
    147  *     conf_table - pointer to the buffers configuration table
    148  *     size       - number of entries in configuration table
    149  *
    150173 * RETURNS:
    151174 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
     
    153176 */
    154177rtems_status_code
    155 rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size);
    156 
     178rtems_bdbuf_init ();
    157179
    158180/* rtems_bdbuf_get --
     
    178200 *     bufget_sema semaphore obtained by this primitive.
    179201 */
    180 rtems_status_code
    181 rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);
     202  rtems_status_code
     203  rtems_bdbuf_get(dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd);
    182204
    183205/* rtems_bdbuf_read --
     
    202224 *     bufget_sema and transfer_sema semaphores obtained by this primitive.
    203225 */
    204 rtems_status_code
    205 rtems_bdbuf_read(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);
     226  rtems_status_code
     227  rtems_bdbuf_read(dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd);
    206228
    207229/* rtems_bdbuf_release --
     
    224246 *     flush_sema and bufget_sema semaphores may be released by this primitive.
    225247 */
    226 rtems_status_code
    227 rtems_bdbuf_release(bdbuf_buffer *bd_buf);
     248  rtems_status_code
     249  rtems_bdbuf_release(rtems_bdbuf_buffer* bd);
    228250
    229251/* rtems_bdbuf_release_modified --
     
    245267 *     flush_sema semaphore may be released by this primitive.
    246268 */
    247 rtems_status_code
    248 rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf);
     269  rtems_status_code
     270  rtems_bdbuf_release_modified(rtems_bdbuf_buffer* bd);
    249271
    250272/* rtems_bdbuf_sync --
     
    266288 *     Primitive may be blocked on transfer_sema semaphore.
    267289 */
    268 rtems_status_code
    269 rtems_bdbuf_sync(bdbuf_buffer *bd_buf);
     290  rtems_status_code
     291  rtems_bdbuf_sync(rtems_bdbuf_buffer* bd);
    270292
    271293/* rtems_bdbuf_syncdev --
     
    280302 *     or error code if error is occured)
    281303 */
    282 rtems_status_code
    283 rtems_bdbuf_syncdev(dev_t dev);
     304  rtems_status_code
     305  rtems_bdbuf_syncdev(dev_t dev);
    284306
    285307/* rtems_bdbuf_find_pool --
     
    298320 *     is not configured.
    299321 */
    300 rtems_status_code
    301 rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool);
     322  rtems_status_code
     323  rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool);
    302324
    303325/* rtems_bdbuf_get_pool_info --
     
    317339 *     Buffer pools enumerated contiguously starting from 0.
    318340 */
    319 rtems_status_code
    320 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks);
     341  rtems_status_code
     342  rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks);
    321343
    322344#ifdef __cplusplus
  • cpukit/libblock/include/rtems/blkdev.h

    r1b39f18 r3899a537  
    2121#endif
    2222
    23 /* Interface with device drivers
    24  * Block device looks, initialized and behaves like traditional RTEMS device
    25  * driver. Heart of the block device driver is in BIOREQUEST ioctl. This call
    26  * puts I/O request to the block device queue, in priority order, for
    27  * asynchronous processing. When driver executes request, req_done
    28  * function invoked, so callee knows about it. Look for details below.
     23/*
     24 *  Interface with device drivers Block device looks, initialized and behaves
     25 * like traditional RTEMS device driver. Heart of the block device driver is in
     26 * BIOREQUEST ioctl. This call puts I/O request to the block device queue, in
     27 * priority order, for asynchronous processing. When driver executes request,
     28 * req_done function invoked, so callee knows about it. Look for details below.
    2929 */
    3030
    31 
    32 /* Block device block number datatype */
    33 typedef uint32_t   blkdev_bnum;
     31/*
     32 * Block device block number datatype
     33 */
     34typedef uint32_t rtems_blkdev_bnum;
    3435
    3536/* Block device request type */
    36 typedef enum blkdev_request_op {
    37     BLKDEV_REQ_READ,  /* Read operation */
    38     BLKDEV_REQ_WRITE  /* Write operation */
    39 } blkdev_request_op;
     37typedef enum rtems_blkdev_request_op {
     38    RTEMS_BLKDEV_REQ_READ,     /* Read operation */
     39    RTEMS_BLKDEV_REQ_WRITE,    /* Write operation */
     40    RTEMS_BLKDEV_CAPABILITIES  /* Capabilities request */
     41} rtems_blkdev_request_op;
    4042
    41 /* Type for block device request done callback function.
     43/**
     44 * ATA multi-sector buffer requests only supported. This option
     45 * means the cache will only supply multiple buffers that are
     46 * inorder so the ATA multi-sector command can be used. This is a
     47 * hack to work around the current ATA driver.
     48 */
     49#define RTEMS_BLKDEV_CAP_MULTISECTOR_CONT (1 << 0)
     50
     51/*
     52 * @typedef rtems_blkdev_request_cb
    4253 *
    43  * PARAMETERS:
    44  *     arg    - argument supplied in blkdev_request
    45  *     status - rtems status code for this operation
    46  *     errno  - errno value to be passed to the user when
     54 * Type for block device request done callback function.
     55 *
     56 * @param arg Argument supplied in blkdev_request
     57 * @param status RTEMS status code for this operation
     58 * @param errno errno value to be passed to the user when
    4759 *              status != RTEMS_SUCCESSFUL
    4860 */
    49 typedef void (* blkdev_request_cb)(void *arg,
    50                                    rtems_status_code status,
    51                                    int error);
     61typedef void (* rtems_blkdev_request_cb)(void *arg,
     62                                         rtems_status_code status,
     63                                         int error);
    5264
    53 /* blkdev_sg_buffer
     65/**
     66 * @struct rtems_blkdev_sg_buffer
    5467 * Block device scatter/gather buffer structure
    5568 */
    56 typedef struct blkdev_sg_buffer {
     69typedef struct rtems_blkdev_sg_buffer {
     70    uint32_t   block;   /* The block number */
    5771    uint32_t   length;  /* Buffer length */
    58     void            *buffer;  /* Buffer pointer */
    59 } blkdev_sg_buffer;
     72    void      *buffer;  /* Buffer pointer */
     73    void      *user;    /* User pointer */
     74} rtems_blkdev_sg_buffer;
    6075
    6176/* blkdev_request (Block Device Request) structure is
    6277 * used to read/write a number of blocks from/to device.
    6378 */
    64 typedef struct blkdev_request {
    65     blkdev_request_op req;      /* Block device operation (read or write) */
    66     blkdev_request_cb req_done; /* Callback function */
    67     void             *done_arg; /* Argument to be passed to callback function*/
    68     rtems_status_code status;  /* Last I/O operation completion status */
    69     int               error;   /* If status != RTEMS_SUCCESSFUL, this field
    70                                 * contains error code
    71                                 */
    72     blkdev_bnum       start;    /* Start block number */
    73     uint32_t    count;    /* Number of blocks to be exchanged */
    74     uint32_t    bufnum;   /* Number of buffers provided */
     79typedef struct rtems_blkdev_request {
     80    /* Block device operation (read or write) */
     81    rtems_blkdev_request_op req;
     82    /* Callback function */
     83    rtems_blkdev_request_cb req_done;
     84    /* Argument to be passed to callback function*/
     85    void *done_arg;
     86    /* Last I/O operation completion status */
     87    rtems_status_code status;
     88    /* If status != RTEMS_SUCCESSFUL, this field contains error code */
     89    int error;
     90    /* Start block number */
     91    rtems_blkdev_bnum start;
     92    /* Number of blocks to be exchanged */
     93    uint32_t count;
     94    /* Number of buffers provided */
     95    uint32_t bufnum;
    7596
    76     blkdev_sg_buffer  bufs[0];/* List of scatter/gather buffers */
    77 } blkdev_request;
     97    /* The task requesting the IO operation. */
     98    rtems_id io_task;
     99
     100    /* List of scatter/gather buffers */
     101    rtems_blkdev_sg_buffer bufs[0];
     102} rtems_blkdev_request;
    78103
    79104/* Block device IOCTL request codes */
    80 #define BLKIO_REQUEST      _IOWR('B', 1, blkdev_request)
    81 #define BLKIO_GETBLKSIZE   _IO('B', 2)
    82 #define BLKIO_GETSIZE      _IO('B', 3)
    83 #define BLKIO_SYNCDEV      _IO('B', 4)
     105#define RTEMS_BLKIO_REQUEST      _IOWR('B', 1, rtems_blkdev_request)
     106#define RTEMS_BLKIO_GETBLKSIZE   _IO('B', 2)
     107#define RTEMS_BLKIO_GETSIZE      _IO('B', 3)
     108#define RTEMS_BLKIO_SYNCDEV      _IO('B', 4)
    84109
    85110/* Device driver interface conventions suppose that driver may
     
    91116 */
    92117
    93 #define GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \
     118#define RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \
    94119      rtems_blkdev_generic_open, rtems_blkdev_generic_close, \
    95120      rtems_blkdev_generic_read, rtems_blkdev_generic_write, \
  • cpukit/libblock/include/rtems/diskdevs.h

    r1b39f18 r3899a537  
    2222#include <stdlib.h>
    2323
    24 #include "rtems/blkdev.h"
    25 
    2624/* Buffer pool identifier */
    2725typedef int rtems_bdpool_id;
    2826
     27#include "rtems/blkdev.h"
     28
     29/* Driver capabilities. */
     30
    2931/* Block device ioctl handler */
    30 typedef int (* block_device_ioctl) (dev_t dev, uint32_t req, void *argp);
    31 
    32 /* disk_device: Entry of this type created for every disk device (both for
    33  * logical and physical disks).
     32typedef int (* rtems_block_device_ioctl) (dev_t dev, uint32_t req, void *argp);
     33
     34/* rtems_disk_device: Entry of this type created for every disk device
     35 * (both for logical and physical disks).
    3436 * Array of arrays of pointers to disk_device structures maintained. First
    3537 * table indexed by major number and second table indexed by minor number.
     
    3739 * moderated size.
    3840 */
    39 typedef struct disk_device {
    40     dev_t               dev;              /* Device ID (major + minor) */
    41     struct disk_device *phys_dev;         /* Physical device ID (the same
    42                                              as dev if this entry specifies
    43                                              the physical device) */
    44     char               *name;             /* Disk device name */
    45     int                 uses;             /* Use counter. Device couldn't be
    46                                              removed if it is in use. */
    47     int                 start;            /* Starting block number (0 for
    48                                              physical devices, block offset
    49                                              on the related physical device
    50                                              for logical device) */
    51     int                 size;             /* Size of physical or logical disk
    52                                              in disk blocks */
    53     int                 block_size;       /* Size of device block (minimum
    54                                              transfer unit) in bytes
    55                                              (must be power of 2) */
    56     int                 block_size_log2;  /* log2 of block_size */
    57     rtems_bdpool_id     pool;             /* Buffer pool assigned to this
    58                                              device */
    59     block_device_ioctl  ioctl;            /* ioctl handler for this block
    60                                              device */
    61 } disk_device;
     41typedef struct rtems_disk_device {
     42    dev_t                     dev;          /* Device ID (major + minor) */
     43    struct rtems_disk_device *phys_dev;     /* Physical device ID (the same
     44                                               as dev if this entry specifies
     45                                               the physical device) */
     46    uint32_t                  capabilities; /* Driver capabilities. */
     47    char                     *name;         /* Disk device name */
     48    int                       uses;         /* Use counter. Device couldn't be
     49                                               removed if it is in use. */
     50    int                       start;        /* Starting block number (0 for
     51                                               physical devices, block offset
     52                                               on the related physical device
     53                                               for logical device) */
     54    int                       size;         /* Size of physical or logical disk
     55                                               in disk blocks */
     56    int                       block_size;   /* Size of device block (minimum
     57                                               transfer unit) in bytes
     58                                               (must be power of 2) */
     59    int                 block_size_log2;    /* log2 of block_size */
     60    rtems_bdpool_id     pool;               /* Buffer pool assigned to this
     61                                               device */
     62    rtems_block_device_ioctl  ioctl;        /* ioctl handler for this block
     63                                               device */
     64} rtems_disk_device;
    6265
    6366/* rtems_disk_create_phys --
     
    8588rtems_status_code
    8689rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
    87                        block_device_ioctl handler,
     90                       rtems_block_device_ioctl handler,
    8891                       const char *name);
    8992
     
    132135rtems_disk_delete(dev_t dev);
    133136
    134 /* rtems_disk_lookup --
     137/* rtems_disk_obtain --
    135138 *     Find block device descriptor by its device identifier. This function
    136139 *     increment usage counter to 1. User should release disk_device structure
     
    144147 *     exists.
    145148 */
    146 disk_device *
    147 rtems_disk_lookup(dev_t dev);
     149rtems_disk_device *
     150rtems_disk_obtain(dev_t dev);
    148151
    149152/* rtems_disk_release --
     
    160163 */
    161164rtems_status_code
    162 rtems_disk_release(disk_device *dd);
     165rtems_disk_release(rtems_disk_device *dd);
    163166
    164167/* rtems_disk_next --
     
    173176 *     Pointer to the disk descriptor for next disk device, or NULL if all
    174177 *     devices enumerated. */
    175 disk_device *
     178rtems_disk_device *
    176179rtems_disk_next(dev_t dev);
    177180
  • cpukit/libblock/include/rtems/ide_part_table.h

    r1b39f18 r3899a537  
    7878 *      corresponds to the sector on the device
    7979 */
    80 typedef struct sector_data_s
     80typedef struct rtems_sector_data_s
    8181{
    8282    uint32_t   sector_num; /* sector number on the device */
    8383    uint8_t    data[0]; /* raw sector data */
    84 } sector_data_t;
     84} rtems_sector_data_t;
    8585
    8686
     
    8888 * Enum partition types
    8989 * see list at http://ata-atapi.com/hiwtab.htm
     90 *
     91 * @todo Should these have RTEMS before them.
    9092 */
    9193enum {
     
    109111
    110112/* Forward declaration */
    111 struct disk_desc_s;
     113struct rtems_disk_desc_s;
    112114
    113115/*
     
    115117 *      contains all neccessary information about partition
    116118 */
    117 typedef struct part_desc_s {
     119typedef struct rtems_part_desc_s {
    118120    uint8_t             bootable; /* is the partition active */
    119121    uint8_t             sys_type; /* type of partition */
    120122    uint8_t             log_id; /* logical number of partition */
    121     uint32_t            start; /* first partition sector, in absolute numeration */
     123    uint32_t            start; /* first partition sector, in absolute
     124                                * numeration */
    122125    uint32_t            size; /* size in sectors */
    123126    uint32_t            end; /* last partition sector, end = start + size - 1 */
    124     struct disk_desc_s *disk_desc; /* descriptor of disk, partition contains in */
    125     struct part_desc_s *ext_part; /* extended partition containing this one */
     127    struct rtems_disk_desc_s *disk_desc; /* descriptor of disk, partition
     128                                          * contains in */
     129    struct rtems_part_desc_s *ext_part; /* extended partition containing this
     130                                         * one */
    126131
    127132    /* partitions, containing in this one */
    128     struct part_desc_s *sub_part[RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER];
    129 } part_desc_t;
    130 
    131 
    132 
    133 typedef struct disk_desc_s {
     133    struct rtems_part_desc_s *sub_part[RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER];
     134} rtems_part_desc_t;
     135
     136
     137
     138typedef struct rtems_disk_desc_s {
    134139    dev_t        dev; /* device number */
    135140
     
    143148
    144149    /* primary partition descriptors */
    145     part_desc_t *partitions[RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER];
    146 } disk_desc_t;
     150    rtems_part_desc_t *partitions[RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER];
     151} rtems_disk_desc_t;
    147152
    148153#ifdef __cplusplus
     
    161166 */
    162167void
    163 rtems_ide_part_table_free(disk_desc_t *disk_desc);
     168rtems_ide_part_table_free(rtems_disk_desc_t *disk_desc);
    164169
    165170
     
    177182 */
    178183rtems_status_code
    179 rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc);
     184rtems_ide_part_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc);
    180185
    181186
  • cpukit/libblock/include/rtems/nvdisk.h

    r1b39f18 r3899a537  
    165165  uint32_t                        flags;        /**< Set of flags to control
    166166                                                     driver. */
    167   uint32_t                       info_level;   /**< Default info level. */
     167  uint32_t                        info_level;   /**< Default info level. */
    168168} rtems_nvdisk_config;
    169169
  • cpukit/libblock/include/rtems/ramdisk.h

    r1b39f18 r3899a537  
    4848
    4949#define RAMDISK_DRIVER_TABLE_ENTRY \
    50     { ramdisk_initialize, GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES }
     50    { ramdisk_initialize, RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES }
    5151
    5252#ifdef __cplusplus
  • cpukit/libblock/src/bdbuf.c

    r1b39f18 r3899a537  
    1111 */
    1212
     13/**
     14 * @file
     15 *
     16 * The Buffer Descriptor Buffer code implement a cache between the disk
     17 * devices and file systems. The code provides a read ahead and qrite queuing
     18 * to the drivers and fast cache look up using an AVL tree.
     19 *
     20 * The buffers are held in pools based on size. Each pool has buffers and the
     21 * buffers follow this state machine:
     22 *
     23 *                        read
     24 *          +-------------------------------+
     25 *          |                               v
     26 *     +-----------+   read complete +------------+
     27 *     |           |  write complete |            |---------+
     28 *     |   EMPTY   |       +---------|  TRANSFER  |         |
     29 *     |           |       |         |            |<--+     |
     30 *     +-----------+       |         +------------+   |     |
     31 *          ^   | get      v                     swap |     |
     32 *          |   |    +-----------+ modified  +------------+ |
     33 *          |   +--->|           |---------->|            | |
     34 *          |        |  ACCESSED |<----------|  MODIFIED  | |
     35 *          |   +----|           |<--+   get |            | |
     36 *          |   |    +-----------+   |       +------------+ |
     37 *          |   |                    |                      |
     38 *          |   | release        get |                      |
     39 *          |   |                    |                      |
     40 *          |   |    +-----------+   |                      |
     41 *   expire |   +--->|           |---+        read complete |
     42 *          |        |   CACHED  |           write complete |
     43 *          +--------|           |<-------------------------+
     44 *                   +-----------+
     45 *
     46 * Empty buffers are added to the empty list and removed from this queue when a
     47 * caller wishes to access a buffer. This is referred to getting a buffer in
     48 * the code and the event get in the state diagram. The buffer is assigned to a
     49 * block and inserted to the AVL. If the block is to be read by the user and
     50 * not in the cache (empty) it is transfered from the disk into memory. If no
     51 * empty buffers exist the buffer is expired from the cache. Currently the
     52 * least recently used block is expired first. A block being accessed is given
     53 * to the file system layer and not accessable to another requester until
     54 * released back to the cache. If the user has modifed the block it is
     55 * transfered to disk then placed on the LRU list.
     56 *
     57 * The pool have the following lists of buffers:
     58 *
     59 *   empty        - Empty buffers created when the pool is initialised.
     60 *   modided      - Buffers waiting to be written to disk.
     61 *   cached_lru   - Accessed buffers released in least recently used order.
     62 *   cached_unsed - Read ahead buffers that have not been accessed.
     63 *
     64 */
     65
     66/**
     67 * Set to 1 to enable debug tracing.
     68 */
     69#define RTEMS_BDBUF_TRACE 0
     70
    1371#if HAVE_CONFIG_H
    1472#include "config.h"
    1573#endif
    1674
    17 #define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
    1875#include <rtems.h>
     76#include <rtems/error.h>
    1977#include <limits.h>
    2078#include <errno.h>
    2179#include <assert.h>
    2280
     81#if RTEMS_BDBUF_TRACE
     82#include <stdio.h>
     83#endif
     84
    2385#include "rtems/bdbuf.h"
    2486
    25 /* Fatal errors: */
    26 #define BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
    27 #define BLKDEV_FATAL_BDBUF_CONSISTENCY BLKDEV_FATAL_ERROR(1)
    28 #define BLKDEV_FATAL_BDBUF_SWAPOUT     BLKDEV_FATAL_ERROR(2)
    29 
    30 
    31 #define SWAPOUT_TASK_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2)
    32 
    33 #define READ_MULTIPLE
    34 
    35 #if defined(READ_MULTIPLE)
    36 #define READ_AHEAD_MAX_BLK_CNT 32
    37 typedef struct {
    38   blkdev_request   req;
    39   blkdev_sg_buffer sg[READ_AHEAD_MAX_BLK_CNT];
    40 } blkdev_request_read_ahead;
     87/**
     88 * The BD buffer context.
     89 */
     90/* Buffering layer context definition */
     91typedef struct rtems_bdbuf_context {
     92  rtems_bdbuf_pool* pool;      /* Table of buffer pools */
     93  int               npools;    /* Number of entries in pool table */
     94  rtems_id          swapout;   /* Swapout task ID */
     95  boolean           swapout_enabled;
     96} rtems_bdbuf_context;
     97
     98/**
     99 * Fatal errors
     100 */
     101#define RTEMS_BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) |         \
     102                                     ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
     103
     104#define RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY RTEMS_BLKDEV_FATAL_ERROR(1)
     105#define RTEMS_BLKDEV_FATAL_BDBUF_SWAPOUT     RTEMS_BLKDEV_FATAL_ERROR(2)
     106#define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK   RTEMS_BLKDEV_FATAL_ERROR(3)
     107#define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(4)
     108#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_LOCK   RTEMS_BLKDEV_FATAL_ERROR(5)
     109#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(6)
     110#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT   RTEMS_BLKDEV_FATAL_ERROR(7)
     111#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAKE   RTEMS_BLKDEV_FATAL_ERROR(8)
     112#define RTEMS_BLKDEV_FATAL_BDBUF_SO_WAKE     RTEMS_BLKDEV_FATAL_ERROR(9)
     113#define RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM    RTEMS_BLKDEV_FATAL_ERROR(10)
     114#define BLKDEV_FATAL_BDBUF_SWAPOUT_RE        RTEMS_BLKDEV_FATAL_ERROR(11)
     115#define BLKDEV_FATAL_BDBUF_SWAPOUT_TS        RTEMS_BLKDEV_FATAL_ERROR(12)
     116
     117#define RTEMS_BDBUF_TRANSFER_SYNC  RTEMS_EVENT_1
     118#define RTEMS_BDBUF_SWAPOUT_SYNC   RTEMS_EVENT_2
     119
     120#define SWAPOUT_TASK_STACK_SIZE (8 * 1024)
     121
     122/**
     123 * Lock semaphore attributes. This is used for locking type mutexes.
     124 */
     125#define RTEMS_BDBUF_POOL_LOCK_ATTRIBS \
     126  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
     127   RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
     128
     129/**
     130 * Waiter semaphore attributes.
     131 *
     132 * @note Do not configure as inherit priority. If a driver is in the driver
     133 *       initialisation table this locked semaphore will have the IDLE task as
     134 *       the holder and a blocking task will raise the priority of the IDLE
     135 *       task which can cause unsual side effects.
     136 */
     137#define RTEMS_BDBUF_POOL_WAITER_ATTRIBS \
     138  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
     139   RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
     140
    41141/*
    42  * list of bd_bufs related to one transfer request
    43  */
    44 typedef struct {
    45   int cnt;
    46   bdbuf_buffer *bd_bufs[READ_AHEAD_MAX_BLK_CNT];
    47 } read_ahead_bd_buf_group;
     142 * The swap out task.
     143 */
     144static rtems_task rtems_bdbuf_swapout_task(rtems_task_argument arg);
     145
     146/**
     147 * The context of buffering layer.
     148 */
     149static rtems_bdbuf_context rtems_bdbuf_ctx;
     150
     151/**
     152 * Print a message to the bdbuf trace output and flush it.
     153 *
     154 * @param format The format string. See printf for details.
     155 * @param ... The arguments for the format text.
     156 * @return int The number of bytes written to the output.
     157 */
     158#if RTEMS_BDBUF_TRACE
     159boolean rtems_bdbuf_tracer;
     160static void
     161rtems_bdbuf_printf (const char *format, ...)
     162{
     163  va_list args;
     164  va_start (args, format);
     165  if (rtems_bdbuf_tracer)
     166  {
     167    fprintf (stdout, "bdbuf:");
     168    vfprintf (stdout, format, args);
     169    fflush (stdout);
     170  }
     171}
    48172#endif
    49173
    50 typedef struct {
    51   blkdev_request *req;
    52   bdbuf_buffer   **write_store;
    53 } write_tfer_done_arg_t;
    54 
    55 static rtems_task bdbuf_swapout_task(rtems_task_argument unused);
    56 
    57 static rtems_status_code bdbuf_release(bdbuf_buffer *bd_buf);
    58 /*
    59  * maximum number of blocks that might be chained together to one
    60  * write driver call
    61  */
    62 #define SWAP_OUT_MAX_BLK_CNT 32
    63 /*#define SWAP_OUT_MAX_BLK_CNT 1 */
    64 /*
    65  * XXX: this is a global buffer. It is used in the swapout task
    66  * and currently will be reused only after it is no longer in use
    67  *
    68  */
    69 static bdbuf_buffer *bd_buf_write_store[SWAP_OUT_MAX_BLK_CNT];
    70 
    71 /* Block device request with a single buffer provided */
    72 typedef struct blkdev_request1 {
    73     blkdev_request   req;
    74     blkdev_sg_buffer sg[1];
    75 } blkdev_request1;
    76 
    77 /* The context of buffering layer */
    78 struct bdbuf_context rtems_bdbuf_ctx;
    79 
    80 #define SAFE
    81 #ifdef SAFE
    82 typedef rtems_mode preemption_key;
    83 
    84 #define DISABLE_PREEMPTION(key) \
    85     do {                                                               \
    86         rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &(key)); \
    87     } while (0)
    88 
    89 #define ENABLE_PREEMPTION(key) \
    90     do {                                                        \
    91         rtems_mode temp;                                        \
    92         rtems_task_mode((key), RTEMS_PREEMPT_MASK, &temp);      \
    93     } while (0)
    94 
    95 #else
    96 
    97 typedef boolean preemption_key;
    98 
    99 #define DISABLE_PREEMPTION(key) \
    100     do {                                             \
    101         (key) = _Thread_Executing->is_preemptible;   \
    102         _Thread_Executing->is_preemptible = 0;       \
    103     } while (0)
    104 
    105 #define ENABLE_PREEMPTION(key) \
    106     do {                                             \
    107         _Thread_Executing->is_preemptible = (key);   \
    108         if (_Thread_Evaluate_mode())                 \
    109             _Thread_Dispatch();                      \
    110     } while (0)
    111 
     174/**
     175 * The default maximum height of 32 allows for AVL trees having between
     176 * 5,704,880 and 4,294,967,295 nodes, depending on order of insertion.  You may
     177 * change this compile-time constant as you wish.
     178 */
     179#ifndef RTEMS_BDBUF_AVL_MAX_HEIGHT
     180#define RTEMS_BDBUF_AVL_MAX_HEIGHT (32)
    112181#endif
    113182
    114 
    115 /* The default maximum height of 32 allows for AVL trees having
    116    between 5,704,880 and 4,294,967,295 nodes, depending on order of
    117    insertion.  You may change this compile-time constant as you
    118    wish. */
    119 #ifndef AVL_MAX_HEIGHT
    120 #define AVL_MAX_HEIGHT  32
     183/**
     184 * Searches for the node with specified dev/block.
     185 *
     186 * @param root pointer to the root node of the AVL-Tree
     187 * @param dev device search key
     188 * @param block block search key
     189 * @retval NULL node with the specified dev/block is not found
     190 * @return pointer to the node with specified dev/block
     191 */
     192static rtems_bdbuf_buffer *
     193rtems_bdbuf_avl_search (rtems_bdbuf_buffer** root,
     194                        dev_t                dev,
     195                        rtems_blkdev_bnum    block)
     196{
     197  rtems_bdbuf_buffer* p = *root;
     198
     199  while ((p != NULL) && ((p->dev != dev) || (p->block != block)))
     200  {
     201    if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
     202    {
     203      p = p->avl.right;
     204    }
     205    else
     206    {
     207      p = p->avl.left;
     208    }
     209  }
     210
     211  return p;
     212}
     213
     214#if CCJ_REMOVE_IN_IN_CVS
     215/**
     216 * Search in AVL tree for first modified buffer belongs to specified
     217 * disk device.
     218 *
     219 * @param root pointer to the root node of the AVL-Tree
     220 * @param dd - disk device descriptor
     221 * @retval NULL no modified blocks on the disk device
     222 * @return pointer to the modified node
     223 */
     224static rtems_bdbuf_buffer *
     225rtems_bdbuf_avl_search_for_sync (rtems_bdbuf_buffer** root,
     226                                 rtems_disk_device*   dd)
     227{
     228  dev_t                dev = dd->phys_dev->dev;
     229  rtems_blkdev_bnum    block_start = dd->start;
     230  rtems_blkdev_bnum    block_end = dd->start + dd->size - 1;
     231  rtems_bdbuf_buffer*  buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT];
     232  rtems_bdbuf_buffer** buf_prev = buf_stack;
     233  rtems_bdbuf_buffer*  p = *root;
     234
     235  while (p != NULL)
     236  {
     237    if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start)))
     238    {
     239      p = p->avl.right;
     240    }
     241    else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end)))
     242    {
     243      p = p->avl.left;
     244    }
     245    else if (p->state == RTEMS_BDBUF_STATE_MODIFIED)
     246    {
     247      return p;
     248    }
     249    else
     250    {
     251      if (p->avl.right != NULL)
     252      {
     253        *buf_prev++ = p->avl.right;
     254      }
     255      p = p->avl.left;
     256    }
     257
     258    if ((p == NULL) && (buf_prev > buf_stack))
     259    {
     260      p = *--buf_prev;
     261    }
     262  }
     263
     264  return p;
     265}
    121266#endif
    122267
    123 /*
    124  * avl_search --
    125  *     Searches for the node with specified dev/block.
     268/**
     269 * Inserts the specified node to the AVl-Tree.
     270 *
     271 * @param root pointer to the root node of the AVL-Tree
     272 * @param node Pointer to the node to add.
     273 * @retval 0 The node added successfully
     274 * @retval -1 An error occured
     275 */
     276static int
     277rtems_bdbuf_avl_insert(rtems_bdbuf_buffer** root,
     278                       rtems_bdbuf_buffer*  node)
     279{
     280  dev_t             dev = node->dev;
     281  rtems_blkdev_bnum block = node->block;
     282
     283  rtems_bdbuf_buffer*  p = *root;
     284  rtems_bdbuf_buffer*  q;
     285  rtems_bdbuf_buffer*  p1;
     286  rtems_bdbuf_buffer*  p2;
     287  rtems_bdbuf_buffer*  buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT];
     288  rtems_bdbuf_buffer** buf_prev = buf_stack;
     289
     290  boolean modified = FALSE;
     291
     292  if (p == NULL)
     293  {
     294    *root = node;
     295    node->avl.left = NULL;
     296    node->avl.right = NULL;
     297    node->avl.bal = 0;
     298    return 0;
     299  }
     300
     301  while (p != NULL)
     302  {
     303    *buf_prev++ = p;
     304
     305    if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
     306    {
     307      p->avl.cache = 1;
     308      q = p->avl.right;
     309      if (q == NULL)
     310      {
     311        q = node;
     312        p->avl.right = q = node;
     313        break;
     314      }
     315    }
     316    else if ((p->dev != dev) || (p->block != block))
     317    {
     318      p->avl.cache = -1;
     319      q = p->avl.left;
     320      if (q == NULL)
     321      {
     322        q = node;
     323        p->avl.left = q;
     324        break;
     325      }
     326    }
     327    else
     328    {
     329      return -1;
     330    }
     331
     332    p = q;
     333  }
     334
     335  q->avl.left = q->avl.right = NULL;
     336  q->avl.bal = 0;
     337  modified = TRUE;
     338  buf_prev--;
     339
     340  while (modified)
     341  {
     342    if (p->avl.cache == -1)
     343    {
     344      switch (p->avl.bal)
     345      {
     346        case 1:
     347          p->avl.bal = 0;
     348          modified = FALSE;
     349          break;
     350
     351        case 0:
     352          p->avl.bal = -1;
     353          break;
     354
     355        case -1:
     356          p1 = p->avl.left;
     357          if (p1->avl.bal == -1) /* simple LL-turn */
     358          {
     359            p->avl.left = p1->avl.right;
     360            p1->avl.right = p;
     361            p->avl.bal = 0;
     362            p = p1;
     363          }
     364          else /* double LR-turn */
     365          {
     366            p2 = p1->avl.right;
     367            p1->avl.right = p2->avl.left;
     368            p2->avl.left = p1;
     369            p->avl.left = p2->avl.right;
     370            p2->avl.right = p;
     371            if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0;
     372            if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
     373            p = p2;
     374          }
     375          p->avl.bal = 0;
     376          modified = FALSE;
     377          break;
     378
     379        default:
     380          break;
     381      }
     382    }
     383    else
     384    {
     385      switch (p->avl.bal)
     386      {
     387        case -1:
     388          p->avl.bal = 0;
     389          modified = FALSE;
     390          break;
     391
     392        case 0:
     393          p->avl.bal = 1;
     394          break;
     395
     396        case 1:
     397          p1 = p->avl.right;
     398          if (p1->avl.bal == 1) /* simple RR-turn */
     399          {
     400            p->avl.right = p1->avl.left;
     401            p1->avl.left = p;
     402            p->avl.bal = 0;
     403            p = p1;
     404          }
     405          else /* double RL-turn */
     406          {
     407            p2 = p1->avl.left;
     408            p1->avl.left = p2->avl.right;
     409            p2->avl.right = p1;
     410            p->avl.right = p2->avl.left;
     411            p2->avl.left = p;
     412            if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
     413            if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0;
     414            p = p2;
     415          }
     416          p->avl.bal = 0;
     417          modified = FALSE;
     418          break;
     419
     420        default:
     421          break;
     422      }
     423    }
     424    q = p;
     425    if (buf_prev > buf_stack)
     426    {
     427      p = *--buf_prev;
     428
     429      if (p->avl.cache == -1)
     430      {
     431        p->avl.left = q;
     432      }
     433      else
     434      {
     435        p->avl.right = q;
     436      }
     437    }
     438    else
     439    {
     440      *root = p;
     441      break;
     442    }
     443  };
     444
     445  return 0;
     446}
     447
     448
     449/**
     450 * Removes the node from the tree.
     451 *
     452 * @param root_addr Pointer to pointer to the root node
     453 * @param node Pointer to the node to remove
     454 * @retval 0 Item removed
     455 * @retval -1 No such item found
     456 */
     457static int
     458rtems_bdbuf_avl_remove(rtems_bdbuf_buffer**      root,
     459                       const rtems_bdbuf_buffer* node)
     460{
     461  dev_t             dev = node->dev;
     462  rtems_blkdev_bnum block = node->block;
     463
     464  rtems_bdbuf_buffer*  p = *root;
     465  rtems_bdbuf_buffer*  q;
     466  rtems_bdbuf_buffer*  r;
     467  rtems_bdbuf_buffer*  s;
     468  rtems_bdbuf_buffer*  p1;
     469  rtems_bdbuf_buffer*  p2;
     470  rtems_bdbuf_buffer*  buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT];
     471  rtems_bdbuf_buffer** buf_prev = buf_stack;
     472
     473  boolean modified = FALSE;
     474
     475  memset (buf_stack, 0, sizeof(buf_stack));
     476
     477  while (p != NULL)
     478  {
     479    *buf_prev++ = p;
     480
     481    if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
     482    {
     483      p->avl.cache = 1;
     484      p = p->avl.right;
     485    }
     486    else if ((p->dev != dev) || (p->block != block))
     487    {
     488      p->avl.cache = -1;
     489      p = p->avl.left;
     490    }
     491    else
     492    {
     493      /* node found */
     494      break;
     495    }
     496  }
     497
     498  if (p == NULL)
     499  {
     500    /* there is no such node */
     501    return -1;
     502  }
     503
     504  q = p;
     505
     506  buf_prev--;
     507  if (buf_prev > buf_stack)
     508  {
     509    p = *(buf_prev - 1);
     510  }
     511  else
     512  {
     513    p = NULL;
     514  }
     515
     516  /* at this moment q - is a node to delete, p is q's parent */
     517  if (q->avl.right == NULL)
     518  {
     519    r = q->avl.left;
     520    if (r != NULL)
     521    {
     522      r->avl.bal = 0;
     523    }
     524    q = r;
     525  }
     526  else
     527  {
     528    rtems_bdbuf_buffer **t;
     529
     530    r = q->avl.right;
     531
     532    if (r->avl.left == NULL)
     533    {
     534      r->avl.left = q->avl.left;
     535      r->avl.bal = q->avl.bal;
     536      r->avl.cache = 1;
     537      *buf_prev++ = q = r;
     538    }
     539    else
     540    {
     541      t = buf_prev++;
     542      s = r;
     543
     544      while (s->avl.left != NULL)
     545      {
     546        *buf_prev++ = r = s;
     547        s = r->avl.left;
     548        r->avl.cache = -1;
     549      }
     550
     551      s->avl.left = q->avl.left;
     552      r->avl.left = s->avl.right;
     553      s->avl.right = q->avl.right;
     554      s->avl.bal = q->avl.bal;
     555      s->avl.cache = 1;
     556
     557      *t = q = s;
     558    }
     559  }
     560
     561  if (p != NULL)
     562  {
     563    if (p->avl.cache == -1)
     564    {
     565      p->avl.left = q;
     566    }
     567    else
     568    {
     569      p->avl.right = q;
     570    }
     571  }
     572  else
     573  {
     574    *root = q;
     575  }
     576
     577  modified = TRUE;
     578
     579  while (modified)
     580  {
     581    if (buf_prev > buf_stack)
     582    {
     583      p = *--buf_prev;
     584    }
     585    else
     586    {
     587      break;
     588    }
     589
     590    if (p->avl.cache == -1)
     591    {
     592      /* rebalance left branch */
     593      switch (p->avl.bal)
     594      {
     595        case -1:
     596          p->avl.bal = 0;
     597          break;
     598        case  0:
     599          p->avl.bal = 1;
     600          modified = FALSE;
     601          break;
     602
     603        case +1:
     604          p1 = p->avl.right;
     605
     606          if (p1->avl.bal >= 0) /* simple RR-turn */
     607          {
     608            p->avl.right = p1->avl.left;
     609            p1->avl.left = p;
     610
     611            if (p1->avl.bal == 0)
     612            {
     613              p1->avl.bal = -1;
     614              modified = FALSE;
     615            }
     616            else
     617            {
     618              p->avl.bal = 0;
     619              p1->avl.bal = 0;
     620            }
     621            p = p1;
     622          }
     623          else /* double RL-turn */
     624          {
     625            p2 = p1->avl.left;
     626
     627            p1->avl.left = p2->avl.right;
     628            p2->avl.right = p1;
     629            p->avl.right = p2->avl.left;
     630            p2->avl.left = p;
     631
     632            if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
     633            if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0;
     634
     635            p = p2;
     636            p2->avl.bal = 0;
     637          }
     638          break;
     639
     640        default:
     641          break;
     642      }
     643    }
     644    else
     645    {
     646      /* rebalance right branch */
     647      switch (p->avl.bal)
     648      {
     649        case +1:
     650          p->avl.bal = 0;
     651          break;
     652
     653        case  0:
     654          p->avl.bal = -1;
     655          modified = FALSE;
     656          break;
     657
     658        case -1:
     659          p1 = p->avl.left;
     660
     661          if (p1->avl.bal <= 0) /* simple LL-turn */
     662          {
     663            p->avl.left = p1->avl.right;
     664            p1->avl.right = p;
     665            if (p1->avl.bal == 0)
     666            {
     667              p1->avl.bal = 1;
     668              modified = FALSE;
     669            }
     670            else
     671            {
     672              p->avl.bal = 0;
     673              p1->avl.bal = 0;
     674            }
     675            p = p1;
     676          }
     677          else /* double LR-turn */
     678          {
     679            p2 = p1->avl.right;
     680
     681            p1->avl.right = p2->avl.left;
     682            p2->avl.left = p1;
     683            p->avl.left = p2->avl.right;
     684            p2->avl.right = p;
     685
     686            if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0;
     687            if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
     688
     689            p = p2;
     690            p2->avl.bal = 0;
     691          }
     692          break;
     693
     694        default:
     695          break;
     696      }
     697    }
     698
     699    if (buf_prev > buf_stack)
     700    {
     701      q = *(buf_prev - 1);
     702
     703      if (q->avl.cache == -1)
     704      {
     705        q->avl.left = p;
     706      }
     707      else
     708      {
     709        q->avl.right = p;
     710      }
     711    }
     712    else
     713    {
     714      *root = p;
     715      break;
     716    }
     717
     718  }
     719
     720  return 0;
     721}
     722
     723/**
     724 * Get the pool for the device.
     725 *
     726 * @param pdd Physical disk device.
     727 */
     728static rtems_bdbuf_pool*
     729rtems_bdbuf_get_pool (const rtems_bdpool_id pid)
     730{
     731  return &rtems_bdbuf_ctx.pool[pid];
     732}
     733
     734/**
     735 * Lock the pool. A single task can nest calls.
     736 *
     737 * @param pool The pool to lock.
     738 */
     739static void
     740rtems_bdbuf_lock_pool (rtems_bdbuf_pool* pool)
     741{
     742  rtems_status_code sc = rtems_semaphore_obtain (pool->lock,
     743                                                 RTEMS_WAIT,
     744                                                 RTEMS_NO_TIMEOUT);
     745  if (sc != RTEMS_SUCCESSFUL)
     746    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_LOCK);
     747}
     748
     749/**
     750 * Unlock the pool.
     751 *
     752 * @param pool The pool to unlock.
     753 */
     754static void
     755rtems_bdbuf_unlock_pool (rtems_bdbuf_pool* pool)
     756{
     757  rtems_status_code sc = rtems_semaphore_release (pool->lock);
     758  if (sc != RTEMS_SUCCESSFUL)
     759    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_UNLOCK);
     760}
     761
     762/**
     763 * Lock the pool's sync. A single task can nest calls.
     764 *
     765 * @param pool The pool's sync to lock.
     766 */
     767static void
     768rtems_bdbuf_lock_sync (rtems_bdbuf_pool* pool)
     769{
     770  rtems_status_code sc = rtems_semaphore_obtain (pool->sync_lock,
     771                                                 RTEMS_WAIT,
     772                                                 RTEMS_NO_TIMEOUT);
     773  if (sc != RTEMS_SUCCESSFUL)
     774    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK);
     775}
     776
     777/**
     778 * Unlock the pool's sync.
     779 *
     780 * @param pool The pool's sync to unlock.
     781 */
     782static void
     783rtems_bdbuf_unlock_sync (rtems_bdbuf_pool* pool)
     784{
     785  rtems_status_code sc = rtems_semaphore_release (pool->sync_lock);
     786  if (sc != RTEMS_SUCCESSFUL)
     787    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK);
     788}
     789
     790/**
     791 * Wait until woken. Semaphores are used so a number of tasks can wait and
     792 * can be woken at once. Task events would require we maintain a list
     793 * of tasks to be woken and this would require storgage and we do not
     794 * know the number of tasks that could be waiting.
     795 *
     796 * While we have the pool locked we can try and claim the semaphore and
     797 * therefore know when we release the lock to the pool we will block until the
     798 * semaphore is released. This may even happen before we get to block.
     799 *
     800 * A counter is used to save the release call when no one is waiting.
     801 *
     802 * The function assumes the pool is locked on entry and it will have locked
     803 * the pool on exit.
     804 *
     805 * @param pool The pool to wait for a buffer to return.
     806 * @param sema The semaphore to block on and wait.
     807 * @param waiters The wait counter for this semaphore.
     808 */
     809static void
     810rtems_bdbuf_wait (rtems_bdbuf_pool* pool, rtems_id* sema,
     811                  volatile uint32_t* waiters)
     812{
     813  rtems_status_code sc;
     814  rtems_mode        prev_mode;
     815 
     816  /*
     817   * Indicate we are waiting.
     818   */
     819  *waiters += 1;
     820
     821  /*
     822   * Disable preemption then unlock the pool and block.
     823   * There is no POSIX condition variable in the core API so
     824   * this is a work around.
     825   *
     826   * The issue is a task could preempt after the pool is unlocked
     827   * because it is blocking or just hits that window, and before
     828   * this task has blocked on the semaphore. If the preempting task
     829   * flushes the queue this task will not see the flush and may
     830   * block for ever or until another transaction flushes this
     831   * semaphore.
     832   */
     833  sc = rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode);
     834
     835  if (sc != RTEMS_SUCCESSFUL)
     836    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT);
     837 
     838  /*
     839   * Unlock the pool, wait, and lock the pool when we return.
     840   */
     841  rtems_bdbuf_unlock_pool (pool);
     842
     843  sc = rtems_semaphore_obtain (*sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     844 
     845  if (sc != RTEMS_UNSATISFIED)
     846    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT);
     847 
     848  rtems_bdbuf_lock_pool (pool);
     849
     850  sc = rtems_task_mode (prev_mode, RTEMS_ALL_MODE_MASKS, &prev_mode);
     851
     852  if (sc != RTEMS_SUCCESSFUL)
     853    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT);
     854 
     855  *waiters -= 1;
     856}
     857
     858/**
     859 * Wake a blocked resource. The resource has a counter that lets us know if
     860 * there are any waiters.
     861 *
     862 * @param sema The semaphore to release.
     863 * @param waiters The wait counter for this semaphore.
     864 */
     865static void
     866rtems_bdbuf_wake (rtems_id sema, volatile uint32_t* waiters)
     867{
     868  if (*waiters)
     869  {
     870    rtems_status_code sc;
     871
     872    sc = rtems_semaphore_flush (sema);
     873 
     874    if (sc != RTEMS_SUCCESSFUL)
     875      rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAKE);
     876  }
     877}
     878
     879/**
     880 * Add a buffer descriptor to the modified list. This modified list is treated
     881 * a litte differently to the other lists. To access it you must have the pool
     882 * locked and this is assumed to be the case on entry to this call and you must
     883 * hold the sync lock. The sync lock is used to block writes while a sync is
     884 * active.
     885 *
     886 * @param sema The semaphore to release.
     887 * @param waiters The wait counter for this semaphore.
     888 */
     889static void
     890rtems_bdbuf_append_modified (rtems_bdbuf_pool* pool, rtems_bdbuf_buffer* bd)
     891{
     892  /*
     893   * Take a copy of the sync_active variable as it will change after
     894   * we unlock the pool and wait for the sync to finish.
     895   */
     896  int sync_active = pool->sync_active;
     897  if (0 && sync_active)
     898  {
     899    rtems_bdbuf_unlock_pool (pool);
     900    rtems_bdbuf_lock_sync (pool);
     901    rtems_bdbuf_lock_pool (pool);
     902  }
     903     
     904  bd->state = RTEMS_BDBUF_STATE_MODIFIED;
     905
     906  rtems_chain_append (&pool->modified, &bd->link);
     907
     908  if (0 && sync_active)
     909    rtems_bdbuf_unlock_sync (pool);
     910}
     911
     912static void
     913rtems_bdbuf_wake_swapper ()
     914{
     915  rtems_status_code sc = rtems_event_send (rtems_bdbuf_ctx.swapout,
     916                                           RTEMS_BDBUF_SWAPOUT_SYNC);
     917  if (sc != RTEMS_SUCCESSFUL)
     918    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_WAKE);
     919}
     920
     921/* bdbuf_initialize_pool --
     922 *      Initialize single buffer pool.
    126923 *
    127924 * PARAMETERS:
    128  *     root - pointer to the root node of the AVL-Tree.
    129  *     dev, block - search key
     925 *     config - buffer pool configuration
     926 *     pool   - pool number
    130927 *
    131928 * RETURNS:
    132  *     NULL if node with specified dev/block not found
    133  *     non-NULL - pointer to the node with specified dev/block
    134  */
    135 static bdbuf_buffer *
    136 avl_search(bdbuf_buffer **root, dev_t dev, blkdev_bnum block)
    137 {
    138     bdbuf_buffer *p = *root;
    139 
    140     while ((p != NULL) && ((p->dev != dev) || (p->block != block)))
    141     {
    142         if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
     929 *     RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
     930 *     code if error occured.
     931 */
     932static rtems_status_code
     933rtems_bdbuf_initialize_pool (rtems_bdbuf_pool_config* config,
     934                             rtems_bdpool_id          pid)
     935{
     936  unsigned char*      buffer = config->mem_area;
     937  rtems_bdbuf_pool*   pool;
     938  rtems_bdbuf_buffer* bd;
     939  rtems_status_code   sc;
     940  int                 b;
     941
     942  pool = rtems_bdbuf_get_pool (pid);
     943 
     944  pool->blksize = config->size;
     945  pool->nblks   = config->num;
     946  pool->tree    = NULL;
     947  pool->buffers = NULL;
     948
     949  rtems_chain_initialize_empty (&pool->ready);
     950  rtems_chain_initialize_empty (&pool->lru);
     951  rtems_chain_initialize_empty (&pool->modified);
     952  rtems_chain_initialize_empty (&pool->sync);
     953
     954  pool->access = 0;
     955  pool->access_waiters = 0;
     956  pool->transfer = 0;
     957  pool->transfer_waiters = 0;
     958  pool->waiting = 0;
     959  pool->wait_waiters = 0;
     960 
     961  /*
     962   * Allocate memory for buffer descriptors
     963   */
     964  pool->bds = calloc (config->num, sizeof (rtems_bdbuf_buffer));
     965 
     966  if (!pool->bds)
     967    return RTEMS_NO_MEMORY;
     968
     969  /*
     970   * Allocate memory for buffers if required.
     971   */
     972  if (buffer == NULL)
     973  {
     974    buffer = pool->buffers = malloc (config->num * config->size);
     975    if (!pool->buffers)
     976    {
     977      free (pool->bds);
     978      return RTEMS_NO_MEMORY;
     979    }
     980  }
     981
     982  for (b = 0, bd = pool->bds;
     983       b < pool->nblks;
     984       b++, bd++, buffer += pool->blksize)
     985  {
     986    bd->dev        = -1;
     987    bd->block      = 0;
     988    bd->buffer     = buffer;
     989    bd->avl.left   = NULL;
     990    bd->avl.right  = NULL;
     991    bd->state      = RTEMS_BDBUF_STATE_EMPTY;
     992    bd->pool       = pid;
     993    bd->error      = 0;
     994    bd->waiters    = 0;
     995    bd->hold_timer = 0;
     996   
     997    rtems_chain_append (&pool->ready, &bd->link);
     998  }
     999
     1000  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'L'),
     1001                               1, RTEMS_BDBUF_POOL_LOCK_ATTRIBS, 0,
     1002                               &pool->lock);
     1003  if (sc != RTEMS_SUCCESSFUL)
     1004  {
     1005    free (pool->buffers);
     1006    free (pool->bds);
     1007    return sc;
     1008  }
     1009
     1010  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 's'),
     1011                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
     1012                               &pool->sync_lock);
     1013  if (sc != RTEMS_SUCCESSFUL)
     1014  {
     1015    rtems_semaphore_delete (pool->lock);
     1016    free (pool->buffers);
     1017    free (pool->bds);
     1018    return sc;
     1019  }
     1020 
     1021  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'a'),
     1022                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
     1023                               &pool->access);
     1024  if (sc != RTEMS_SUCCESSFUL)
     1025  {
     1026    rtems_semaphore_delete (pool->sync_lock);
     1027    rtems_semaphore_delete (pool->lock);
     1028    free (pool->buffers);
     1029    free (pool->bds);
     1030    return sc;
     1031  }
     1032
     1033  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 't'),
     1034                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
     1035                               &pool->transfer);
     1036  if (sc != RTEMS_SUCCESSFUL)
     1037  {
     1038    rtems_semaphore_delete (pool->access);
     1039    rtems_semaphore_delete (pool->sync_lock);
     1040    rtems_semaphore_delete (pool->lock);
     1041    free (pool->buffers);
     1042    free (pool->bds);
     1043    return sc;
     1044  }
     1045
     1046  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'w'),
     1047                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
     1048                               &pool->waiting);
     1049  if (sc != RTEMS_SUCCESSFUL)
     1050  {
     1051    rtems_semaphore_delete (pool->transfer);
     1052    rtems_semaphore_delete (pool->access);
     1053    rtems_semaphore_delete (pool->sync_lock);
     1054    rtems_semaphore_delete (pool->lock);
     1055    free (pool->buffers);
     1056    free (pool->bds);
     1057    return sc;
     1058  }
     1059
     1060  return RTEMS_SUCCESSFUL;
     1061}
     1062
     1063/* bdbuf_release_pool --
     1064 *     Free resources allocated for buffer pool with specified number.
     1065 *
     1066 * PARAMETERS:
     1067 *     pool - buffer pool number
     1068 *
     1069 * RETURNS:
     1070 *     RTEMS_SUCCESSFUL
     1071 */
     1072static rtems_status_code
     1073rtems_bdbuf_release_pool (rtems_bdpool_id pid)
     1074{
     1075  rtems_bdbuf_pool* pool = rtems_bdbuf_get_pool (pid);
     1076 
     1077  rtems_bdbuf_lock_pool (pool);
     1078
     1079  rtems_semaphore_delete (pool->waiting);
     1080  rtems_semaphore_delete (pool->transfer);
     1081  rtems_semaphore_delete (pool->access);
     1082  rtems_semaphore_delete (pool->lock);
     1083 
     1084  free (pool->buffers);
     1085  free (pool->bds);
     1086 
     1087  return RTEMS_SUCCESSFUL;
     1088}
     1089
     1090/* rtems_bdbuf_init --
     1091 *     Prepare buffering layer to work - initialize buffer descritors
     1092 *     and (if it is neccessary) buffers. Buffers will be allocated according
     1093 *     to the configuration table, each entry describes kind of block and
     1094 *     amount requested. After initialization all blocks are placed onto
     1095 *     empty elements lists.
     1096 *
     1097 * PARAMETERS:
     1098 *     conf_table - pointer to the buffers configuration table
     1099 *     size       - number of entries in configuration table
     1100 *
     1101 * RETURNS:
     1102 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
     1103 *     or error code if error is occured)
     1104 */
     1105rtems_status_code
     1106rtems_bdbuf_init ()
     1107{
     1108  rtems_bdpool_id   p;
     1109  rtems_status_code sc;
     1110
     1111#if RTEMS_BDBUF_TRACE
     1112  rtems_bdbuf_printf ("init\n");
     1113#endif
     1114
     1115  if (rtems_bdbuf_pool_configuration_size <= 0)
     1116    return RTEMS_INVALID_SIZE;
     1117
     1118  if (rtems_bdbuf_ctx.npools)
     1119    return RTEMS_RESOURCE_IN_USE;
     1120
     1121  rtems_bdbuf_ctx.npools = rtems_bdbuf_pool_configuration_size;
     1122
     1123  /*
     1124   * Allocate memory for buffer pool descriptors
     1125   */
     1126  rtems_bdbuf_ctx.pool = calloc (rtems_bdbuf_pool_configuration_size,
     1127                                 sizeof (rtems_bdbuf_pool));
     1128 
     1129  if (rtems_bdbuf_ctx.pool == NULL)
     1130    return RTEMS_NO_MEMORY;
     1131
     1132  /*
     1133   * Initialize buffer pools and roll out if something failed,
     1134   */
     1135  for (p = 0; p < rtems_bdbuf_ctx.npools; p++)
     1136  {
     1137    sc = rtems_bdbuf_initialize_pool (&rtems_bdbuf_pool_configuration[p], p);
     1138    if (sc != RTEMS_SUCCESSFUL)
     1139    {
     1140      rtems_bdpool_id j;
     1141      for (j = 0; j < p - 1; j++)
     1142        rtems_bdbuf_release_pool (j);
     1143      return sc;
     1144    }
     1145  }
     1146
     1147  /*
     1148   * Create and start swapout task
     1149   */
     1150
     1151  rtems_bdbuf_ctx.swapout_enabled = TRUE;
     1152 
     1153  sc = rtems_task_create (rtems_build_name('B', 'S', 'W', 'P'),
     1154                          (rtems_bdbuf_configuration.swapout_priority ?
     1155                           rtems_bdbuf_configuration.swapout_priority :
     1156                           RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT),
     1157                          SWAPOUT_TASK_STACK_SIZE,
     1158                          RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
     1159                          RTEMS_LOCAL | RTEMS_NO_FLOATING_POINT,
     1160                          &rtems_bdbuf_ctx.swapout);
     1161  if (sc != RTEMS_SUCCESSFUL)
     1162  {
     1163    for (p = 0; p < rtems_bdbuf_ctx.npools; p++)
     1164      rtems_bdbuf_release_pool (p);
     1165    free (rtems_bdbuf_ctx.pool);
     1166    return sc;
     1167  }
     1168
     1169  sc = rtems_task_start (rtems_bdbuf_ctx.swapout,
     1170                         rtems_bdbuf_swapout_task,
     1171                         (rtems_task_argument) &rtems_bdbuf_ctx);
     1172  if (sc != RTEMS_SUCCESSFUL)
     1173  {
     1174    rtems_task_delete (rtems_bdbuf_ctx.swapout);
     1175    for (p = 0; p < rtems_bdbuf_ctx.npools; p++)
     1176      rtems_bdbuf_release_pool (p);
     1177    free (rtems_bdbuf_ctx.pool);
     1178    return sc;
     1179  }
     1180
     1181  return RTEMS_SUCCESSFUL;
     1182}
     1183
     1184/**
     1185 * Get a buffer for this device and block. This function returns a buffer once
     1186 * placed into the AVL tree. If no buffer is available and it is not a read
     1187 * ahead request wait until one is available. If the buffer is for a read ahead
     1188 * transfer return NULL if there is not buffer or it is in the cache.
     1189 *
     1190 * The AVL tree of buffers for the pool is searched and if not located check
     1191 * obtain a buffer and insert it into the AVL tree. Buffers are first obtained
     1192 * from the ready list until all empty buffers are used. Once all buffers are
     1193 * in use buffers are taken from the LRU list with the least recently used
     1194 * buffer taken first. A buffer taken from the LRU list is removed from the AVL
     1195 * tree. The empty list or LRU list buffer is initialised to this device and
     1196 * block. If no buffers are available due to the empty and LRU lists being
     1197 * empty the caller is blocked on the waiting semaphore and counter. When
     1198 * buffers return from the upper layers (access) or lower driver (transfer) the
     1199 * blocked caller task is woken and this procedure is repeated. The repeat
     1200 * handles a case of a another thread pre-empting getting a buffer first and
     1201 * adding it to the AVL tree.
     1202 *
     1203 * A buffer located in the AVL tree means it is already in the cache and maybe
     1204 * in use somewhere. The buffer can be either:
     1205 *
     1206 * # Cached. Not being accessed or part of a media transfer.
     1207 * # Access. Is with an upper layer being accessed.
     1208 * # Transfer. Is with the driver and part of a media transfer.
     1209 *
     1210 * If cached we assign the state new state extract it from any list it maybe
     1211 * part of and return to the user. The buffer could be part of the LRU list or
     1212 * the modifed list waiting to be swapped out by the swap out task.
     1213 *
     1214 * This function assumes the pool the buffer is being taken from is locked and
     1215 * it insure the pool is locked when it returns.
     1216 *
     1217 * @param device The physical disk device
     1218 * @param block  Linear media block number
     1219 * @param
     1220 * @param bd     Address to store of found descriptor
     1221
     1222 * RETURNS:
     1223 *     RTEMS status code ( if operation completed successfully
     1224 *     or error code if error is occured)
     1225 *
     1226 * SIDE EFFEECTS:
     1227 *     bufget_sema may be obtained by this primitive
     1228 *
     1229 * NOTE:
     1230 *     It is assumed that primitive invoked when thread preemption is disabled.
     1231 */
     1232static rtems_bdbuf_buffer*
     1233rtems_bdbuf_get_buffer (rtems_disk_device* pdd,
     1234                        rtems_bdbuf_pool*  pool,
     1235                        rtems_blkdev_bnum  block,
     1236                        boolean            read_ahead)
     1237{
     1238  dev_t               device = pdd->dev;
     1239  rtems_bdbuf_buffer* bd;
     1240  boolean             available;
     1241
     1242  /*
     1243   * Loop until we get a buffer. Under load we could find no buffers are
     1244   * available so in the case of the required block this task needs to wait
     1245   * until some return before proceeding. There is no timeout. If the buffer is
     1246   * for a read ahead buffer return NULL.
     1247   *
     1248   * The search procedure is repeated as another thread could have pre-empted
     1249   * us while we waited for a buffer, obtained an empty buffer and loaded the
     1250   * AVL tree with it.
     1251   */
     1252  do
     1253  {
     1254    /*
     1255     * Search for buffer descriptor for this dev/block key.
     1256     */
     1257    bd = rtems_bdbuf_avl_search (&pool->tree, device, block);
     1258
     1259    /*
     1260     * No buffer in the cache for this block. We need to obtain a buffer and
     1261     * this means take a buffer that is ready to use. If all buffers are in use
     1262     * take the least recently used buffer. If there are none then the cache is
     1263     * empty. All the buffers are either queued to be written to disk or with
     1264     * the user. We cannot do much with the buffers with the user how-ever with
     1265     * the modified buffers waiting to be written to disk flush the maximum
     1266     * number transfered in a block to disk. After this all that be done is to
     1267     * wait for a buffer to return to the cache.
     1268     */
     1269    if (!bd)
     1270    {
     1271      /*
     1272       * Assign new buffer descriptor from the empty list if one is present. If
     1273       * the empty queue is empty get the oldest buffer from LRU list. If the
     1274       * LRU list is empty there are no available buffers so we need to wait
     1275       * until some are returned.
     1276       */
     1277      if (rtems_chain_is_empty (&pool->ready))
     1278      {
     1279        /*
     1280         * No unsed or read-ahead buffers.
     1281         *
     1282         * If this is a read ahead buffer just return. No need to place
     1283         * further pressure on the cache by reading something that may be
     1284         * needed when we have data in the cache that was needed.
     1285         */
     1286        if (read_ahead)
     1287          return NULL;
     1288
     1289        /*
     1290         * Check the LRU list.
     1291         */
     1292        bd = (rtems_bdbuf_buffer *) rtems_chain_get (&pool->lru);
     1293       
     1294        if (bd)
    1431295        {
    144             p = p->avl.right;
     1296          /*
     1297           * Remove the buffer from the AVL tree.
     1298           */
     1299          if (rtems_bdbuf_avl_remove (&pool->tree, bd) != 0)
     1300            rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
    1451301        }
    1461302        else
    1471303        {
    148             p = p->avl.left;
     1304          /*
     1305           * If there are buffers on the modified list expire the hold timer
     1306           * and wake the swap out task.
     1307           */
     1308          if (!rtems_chain_is_empty (&pool->modified))
     1309          {
     1310            rtems_chain_node* node = rtems_chain_head (&pool->modified);
     1311            int               write_blocks = 0;
     1312           
     1313            node = node->next;
     1314            while ((write_blocks < rtems_bdbuf_configuration.max_write_blocks) &&
     1315                   !rtems_chain_is_tail (&pool->modified, node))
     1316            {
     1317              rtems_bdbuf_buffer* bd = (rtems_bdbuf_buffer*) node;
     1318              bd->hold_timer = 0;
     1319              write_blocks++;
     1320              node = node->next;
     1321            }
     1322
     1323            rtems_bdbuf_wake_swapper ();
     1324          }
     1325         
     1326          /*
     1327           * Wait for a buffer to be returned to the pool. The buffer will be
     1328           * placed on the LRU list.
     1329           */
     1330          rtems_bdbuf_wait (pool, &pool->waiting, &pool->wait_waiters);
    1491331        }
    150     }
    151 
    152     return p;
    153 }
    154 
    155 
    156 /* avl_search_for_sync --
    157  *     Search in AVL tree for first modified buffer belongs to specified
    158  *     disk device.
    159  *
    160  * PARAMETERS:
    161  *     root - pointer to tree root
    162  *     dd - disk device descriptor
    163  *
    164  * RETURNS:
    165  *     Block buffer, or NULL if no modified blocks on specified device
    166  *     exists.
    167  */
    168 static bdbuf_buffer *
    169 avl_search_for_sync(bdbuf_buffer **root, disk_device *dd)
    170 {
    171     dev_t dev = dd->phys_dev->dev;
    172     blkdev_bnum block_start = dd->start;
    173     blkdev_bnum block_end = dd->start + dd->size - 1;
    174 
    175     bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
    176     bdbuf_buffer **buf_prev = buf_stack;
    177     bdbuf_buffer *p = *root;
    178 
    179     while (p != NULL)
    180     {
    181         if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start)))
     1332      }
     1333      else
     1334      {
     1335        bd = (rtems_bdbuf_buffer *) rtems_chain_get (&(pool->ready));
     1336
     1337        if ((bd->state != RTEMS_BDBUF_STATE_EMPTY) &&
     1338            (bd->state != RTEMS_BDBUF_STATE_READ_AHEAD))
     1339          rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
     1340
     1341        if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD)
    1821342        {
    183             p = p->avl.right;
     1343          if (rtems_bdbuf_avl_remove (&pool->tree, bd) != 0)
     1344            rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
    1841345        }
    185         else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end)))
    186         {
    187             p = p->avl.left;
    188         }
    189         else if (p->modified)
    190         {
    191             return p;
    192         }
    193         else
    194         {
    195             if (p->avl.right != NULL)
    196             {
    197                 *buf_prev++ = p->avl.right;
    198             }
    199             p = p->avl.left;
    200         }
    201 
    202         if ((p == NULL) && (buf_prev > buf_stack))
    203         {
    204             p = *--buf_prev;
    205         }
    206     }
    207 
    208     return p;
    209 }
    210 
    211 
    212 /*
    213  * avl_insert --
    214  *     Inserts the specified node to the AVl-Tree.
    215  *
    216  * PARAMETERS:
    217  *     root - Pointer to pointer to the root node
    218  *     node - Pointer to the node to add.
    219  *
    220  * RETURNS:
    221  *     0 - The node added successfully
    222  *    -1 - An error occured
    223  */
    224 static int
    225 avl_insert(bdbuf_buffer **root, bdbuf_buffer *node)
    226 {
    227     dev_t dev = node->dev;
    228     blkdev_bnum block = node->block;
    229 
    230     bdbuf_buffer *p = *root;
    231     bdbuf_buffer *q, *p1, *p2;
    232     bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
    233     bdbuf_buffer **buf_prev = buf_stack;
    234 
    235     boolean modified = FALSE;
    236 
    237     if (p == NULL)
    238     {
    239         *root = node;
    240         node->avl.left = NULL;
    241         node->avl.right = NULL;
    242         node->avl.bal = 0;
    243         return 0;
    244     }
    245 
    246     while (p != NULL)
    247     {
    248         *buf_prev++ = p;
    249 
    250         if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
    251         {
    252             p->avl.cache = 1;
    253             q = p->avl.right;
    254             if (q == NULL)
    255             {
    256                 q = node;
    257                 p->avl.right = q = node;
    258                 break;
    259             }
    260         }
    261         else if ((p->dev != dev) || (p->block != block))
    262         {
    263             p->avl.cache = -1;
    264             q = p->avl.left;
    265             if (q == NULL)
    266             {
    267                 q = node;
    268                 p->avl.left = q;
    269                 break;
    270             }
    271         }
    272         else
    273         {
    274             return -1;
    275         }
    276 
    277         p = q;
    278     }
    279 
    280     q->avl.left = q->avl.right = NULL;
    281     q->avl.bal = 0;
    282     modified = TRUE;
    283     buf_prev--;
    284 
    285     while (modified)
    286     {
    287         if (p->avl.cache == -1)
    288         {
    289             switch (p->avl.bal)
    290             {
    291                 case 1:
    292                     p->avl.bal = 0;
    293                     modified = FALSE;
    294                     break;
    295 
    296                 case 0:
    297                     p->avl.bal = -1;
    298                     break;
    299 
    300                 case -1:
    301                     p1 = p->avl.left;
    302                     if (p1->avl.bal == -1) /* simple LL-turn */
    303                     {
    304                         p->avl.left = p1->avl.right;
    305                         p1->avl.right = p;
    306                         p->avl.bal = 0;
    307                         p = p1;
    308                     }
    309                     else /* double LR-turn */
    310                     {
    311                         p2 = p1->avl.right;
    312                         p1->avl.right = p2->avl.left;
    313                         p2->avl.left = p1;
    314                         p->avl.left = p2->avl.right;
    315                         p2->avl.right = p;
    316                         if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0;
    317                         if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
    318                         p = p2;
    319                     }
    320                     p->avl.bal = 0;
    321                     modified = FALSE;
    322                     break;
    323 
    324                 default:
    325                     break;
    326             }
    327         }
    328         else
    329         {
    330             switch (p->avl.bal)
    331             {
    332                 case -1:
    333                     p->avl.bal = 0;
    334                     modified = FALSE;
    335                     break;
    336 
    337                 case 0:
    338                     p->avl.bal = 1;
    339                     break;
    340 
    341                 case 1:
    342                     p1 = p->avl.right;
    343                     if (p1->avl.bal == 1) /* simple RR-turn */
    344                     {
    345                         p->avl.right = p1->avl.left;
    346                         p1->avl.left = p;
    347                         p->avl.bal = 0;
    348                         p = p1;
    349                     }
    350                     else /* double RL-turn */
    351                     {
    352                         p2 = p1->avl.left;
    353                         p1->avl.left = p2->avl.right;
    354                         p2->avl.right = p1;
    355                         p->avl.right = p2->avl.left;
    356                         p2->avl.left = p;
    357                         if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
    358                         if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0;
    359                         p = p2;
    360                     }
    361                     p->avl.bal = 0;
    362                     modified = FALSE;
    363                     break;
    364 
    365                 default:
    366                     break;
    367             }
    368         }
    369         q = p;
    370         if (buf_prev > buf_stack)
    371         {
    372             p = *--buf_prev;
    373 
    374             if (p->avl.cache == -1)
    375             {
    376                 p->avl.left = q;
    377             }
    378             else
    379             {
    380                 p->avl.right = q;
    381             }
    382         }
    383         else
    384         {
    385             *root = p;
    386             break;
    387         }
    388     };
    389 
    390     return 0;
    391 }
    392 
    393 
    394 /* avl_remove --
    395  *     removes the node from the tree.
    396  *
    397  * PARAMETERS:
    398  *     root_addr - Pointer to pointer to the root node
    399  *     node      - Pointer to the node to remove
    400  *
    401  * RETURNS:
    402  *     0 - Item removed
    403  *    -1 - No such item found
    404  */
    405 static int
    406 avl_remove(bdbuf_buffer **root, const bdbuf_buffer *node)
    407 {
    408     dev_t dev = node->dev;
    409     blkdev_bnum block = node->block;
    410 
    411     bdbuf_buffer *p = *root;
    412     bdbuf_buffer *q, *r, *s, *p1, *p2;
    413     bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
    414     bdbuf_buffer **buf_prev = buf_stack;
    415 
    416     boolean modified = FALSE;
    417 
    418     memset(buf_stack, 0, sizeof(buf_stack));
    419 
    420     while (p != NULL)
    421     {
    422         *buf_prev++ = p;
    423 
    424         if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
    425         {
    426             p->avl.cache = 1;
    427             p = p->avl.right;
    428         }
    429         else if ((p->dev != dev) || (p->block != block))
    430         {
    431             p->avl.cache = -1;
    432             p = p->avl.left;
    433         }
    434         else
    435         {
    436             /* node found */
    437             break;
    438         }
    439     }
    440 
    441     if (p == NULL)
    442     {
    443         /* there is no such node */
    444         return -1;
    445     }
    446 
    447     q = p;
    448 
    449     buf_prev--;
    450     if (buf_prev > buf_stack)
    451     {
    452         p = *(buf_prev - 1);
    453     }
    454     else
    455     {
    456         p = NULL;
    457     }
    458 
    459     /* at this moment q - is a node to delete, p is q's parent */
    460     if (q->avl.right == NULL)
    461     {
    462         r = q->avl.left;
    463         if (r != NULL)
    464         {
    465             r->avl.bal = 0;
    466         }
    467         q = r;
    468     }
    469     else
    470     {
    471         bdbuf_buffer **t;
    472 
    473         r = q->avl.right;
    474 
    475         if (r->avl.left == NULL)
    476         {
    477             r->avl.left = q->avl.left;
    478             r->avl.bal = q->avl.bal;
    479             r->avl.cache = 1;
    480             *buf_prev++ = q = r;
    481         }
    482         else
    483         {
    484             t = buf_prev++;
    485             s = r;
    486 
    487             while (s->avl.left != NULL)
    488             {
    489                 *buf_prev++ = r = s;
    490                 s = r->avl.left;
    491                 r->avl.cache = -1;
    492             }
    493 
    494             s->avl.left = q->avl.left;
    495             r->avl.left = s->avl.right;
    496             s->avl.right = q->avl.right;
    497             s->avl.bal = q->avl.bal;
    498             s->avl.cache = 1;
    499 
    500             *t = q = s;
    501         }
    502     }
    503 
    504     if (p != NULL)
    505     {
    506         if (p->avl.cache == -1)
    507         {
    508             p->avl.left = q;
    509         }
    510         else
    511         {
    512             p->avl.right = q;
    513         }
    514     }
    515     else
    516     {
    517         *root = q;
    518     }
    519 
    520     modified = TRUE;
    521 
    522     while (modified)
    523     {
    524         if (buf_prev > buf_stack)
    525         {
    526             p = *--buf_prev;
    527         }
    528         else
    529         {
    530             break;
    531         }
    532 
    533         if (p->avl.cache == -1)
    534         {
    535             /* rebalance left branch */
    536             switch (p->avl.bal)
    537             {
    538                 case -1:
    539                     p->avl.bal = 0;
    540                     break;
    541                 case  0:
    542                     p->avl.bal = 1;
    543                     modified = FALSE;
    544                     break;
    545 
    546                 case +1:
    547                     p1 = p->avl.right;
    548 
    549                     if (p1->avl.bal >= 0) /* simple RR-turn */
    550                     {
    551                         p->avl.right = p1->avl.left;
    552                         p1->avl.left = p;
    553 
    554                         if (p1->avl.bal == 0)
    555                         {
    556                             p1->avl.bal = -1;
    557                             modified = FALSE;
    558                         }
    559                         else
    560                         {
    561                             p->avl.bal = 0;
    562                             p1->avl.bal = 0;
    563                         }
    564                         p = p1;
    565                     }
    566                     else /* double RL-turn */
    567                     {
    568                         p2 = p1->avl.left;
    569 
    570                         p1->avl.left = p2->avl.right;
    571                         p2->avl.right = p1;
    572                         p->avl.right = p2->avl.left;
    573                         p2->avl.left = p;
    574 
    575                         if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
    576                         if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0;
    577 
    578                         p = p2;
    579                         p2->avl.bal = 0;
    580                     }
    581                     break;
    582 
    583                 default:
    584                     break;
    585             }
    586         }
    587         else
    588         {
    589             /* rebalance right branch */
    590             switch (p->avl.bal)
    591             {
    592                 case +1:
    593                     p->avl.bal = 0;
    594                     break;
    595 
    596                 case  0:
    597                     p->avl.bal = -1;
    598                     modified = FALSE;
    599                     break;
    600 
    601                 case -1:
    602                     p1 = p->avl.left;
    603 
    604                     if (p1->avl.bal <= 0) /* simple LL-turn */
    605                     {
    606                         p->avl.left = p1->avl.right;
    607                         p1->avl.right = p;
    608                         if (p1->avl.bal == 0)
    609                         {
    610                             p1->avl.bal = 1;
    611                             modified = FALSE;
    612                         }
    613                         else
    614                         {
    615                             p->avl.bal = 0;
    616                             p1->avl.bal = 0;
    617                         }
    618                         p = p1;
    619                     }
    620                     else /* double LR-turn */
    621                     {
    622                         p2 = p1->avl.right;
    623 
    624                         p1->avl.right = p2->avl.left;
    625                         p2->avl.left = p1;
    626                         p->avl.left = p2->avl.right;
    627                         p2->avl.right = p;
    628 
    629                         if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0;
    630                         if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
    631 
    632                         p = p2;
    633                         p2->avl.bal = 0;
    634                     }
    635                     break;
    636 
    637                 default:
    638                     break;
    639             }
    640         }
    641 
    642         if (buf_prev > buf_stack)
    643         {
    644             q = *(buf_prev - 1);
    645 
    646             if (q->avl.cache == -1)
    647             {
    648                 q->avl.left = p;
    649             }
    650             else
    651             {
    652                 q->avl.right = p;
    653             }
    654         }
    655         else
    656         {
    657             *root = p;
    658             break;
    659         }
    660 
    661     }
    662 
    663     return 0;
    664 }
    665 
    666 /* bdbuf_initialize_pool --
    667  *      Initialize single buffer pool.
    668  *
    669  * PARAMETERS:
    670  *     config - buffer pool configuration
    671  *     pool   - pool number
    672  *
    673  * RETURNS:
    674  *     RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
    675  *     code if error occured.
    676  */
    677 static rtems_status_code
    678 bdbuf_initialize_pool(rtems_bdbuf_config *config, int pool)
    679 {
    680     bdbuf_pool *p = rtems_bdbuf_ctx.pool + pool;
    681     unsigned char *bufs;
    682     bdbuf_buffer *b;
    683     rtems_status_code rc;
    684     int i;
    685 
    686     p->blksize = config->size;
    687     p->nblks = config->num;
    688     p->tree = NULL;
    689 
    690     rtems_chain_initialize_empty(&p->free);
    691     rtems_chain_initialize_empty(&p->lru);
    692 
    693     /* Allocate memory for buffer descriptors */
    694     p->bdbufs = calloc(config->num, sizeof(bdbuf_buffer));
    695     if (p->bdbufs == NULL)
    696     {
    697         return RTEMS_NO_MEMORY;
    698     }
    699 
    700     /* Allocate memory for buffers if required */
    701     if (config->mem_area == NULL)
    702     {
    703         bufs = p->mallocd_bufs = malloc(config->num * config->size);
    704         if (bufs == NULL)
    705         {
    706             free(p->bdbufs);
    707             return RTEMS_NO_MEMORY;
    708         }
    709     }
    710     else
    711     {
    712         bufs = config->mem_area;
    713         p->mallocd_bufs = NULL;
    714     }
    715 
    716     for (i = 0, b = p->bdbufs; i < p->nblks; i++, b++, bufs += p->blksize)
    717     {
    718         b->dev = -1; b->block = 0;
    719         b->buffer = bufs;
    720         b->actual = b->modified = b->in_progress = FALSE;
    721         b->use_count = 0;
    722         b->pool = pool;
    723         rtems_chain_append(&p->free, &b->link);
    724     }
    725 
    726     rc = rtems_semaphore_create(
    727         rtems_build_name('B', 'U', 'F', 'G'),
    728         p->nblks,
    729         RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
    730         RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
    731         0,
    732         &p->bufget_sema);
    733 
    734     if (rc != RTEMS_SUCCESSFUL)
    735     {
    736         free(p->bdbufs);
    737         free(p->mallocd_bufs);
    738         return rc;
    739     }
    740 
    741     return RTEMS_SUCCESSFUL;
    742 }
    743 
    744 /* bdbuf_release_pool --
    745  *     Free resources allocated for buffer pool with specified number.
    746  *
    747  * PARAMETERS:
    748  *     pool - buffer pool number
    749  *
    750  * RETURNS:
    751  *     RTEMS_SUCCESSFUL
    752  */
    753 static rtems_status_code
    754 bdbuf_release_pool(rtems_bdpool_id pool)
    755 {
    756     bdbuf_pool *p = rtems_bdbuf_ctx.pool + pool;
    757     rtems_semaphore_delete(p->bufget_sema);
    758     free(p->bdbufs);
    759     free(p->mallocd_bufs);
    760     return RTEMS_SUCCESSFUL;
    761 }
    762 
    763 /* rtems_bdbuf_init --
    764  *     Prepare buffering layer to work - initialize buffer descritors
    765  *     and (if it is neccessary)buffers. Buffers will be allocated accoriding
    766  *     to the configuration table, each entry describes kind of block and
    767  *     amount requested. After initialization all blocks is placed into
    768  *     free elements lists.
    769  *
    770  * PARAMETERS:
    771  *     conf_table - pointer to the buffers configuration table
    772  *     size       - number of entries in configuration table
    773  *
    774  * RETURNS:
    775  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    776  *     or error code if error is occured)
     1346      }
     1347
     1348      if (bd)
     1349      {
     1350        bd->dev       = device;
     1351        bd->block     = block;
     1352        bd->avl.left  = NULL;
     1353        bd->avl.right = NULL;
     1354        bd->state     = RTEMS_BDBUF_STATE_EMPTY;
     1355        bd->error     = 0;
     1356        bd->waiters   = 0;
     1357
     1358        if (rtems_bdbuf_avl_insert (&pool->tree, bd) != 0)
     1359          rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
     1360
     1361        return bd;
     1362      }
     1363    }
     1364  }
     1365  while (!bd);
     1366
     1367  /*
     1368   * If the buffer is for read ahead and it exists in the AVL cache or is being
     1369   * accessed or being transfered then return NULL.
     1370   */
     1371  if (read_ahead)
     1372    return NULL;
     1373
     1374  /*
     1375   * Loop waiting for the buffer to enter the cached state. If the buffer
     1376   * is in the access or transfer state then wait until it is not.
     1377   */
     1378  available = FALSE;
     1379  while (!available)
     1380  {
     1381    switch (bd->state)
     1382    {
     1383      case RTEMS_BDBUF_STATE_CACHED:
     1384      case RTEMS_BDBUF_STATE_MODIFIED:
     1385      case RTEMS_BDBUF_STATE_READ_AHEAD:
     1386        available = TRUE;
     1387        break;
     1388
     1389      case RTEMS_BDBUF_STATE_ACCESS:
     1390      case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
     1391        bd->waiters++;
     1392        rtems_bdbuf_wait (pool, &pool->access, &pool->access_waiters);
     1393        bd->waiters--;
     1394        break;
     1395
     1396      case RTEMS_BDBUF_STATE_SYNC:
     1397      case RTEMS_BDBUF_STATE_TRANSFER:
     1398        bd->waiters++;
     1399        rtems_bdbuf_wait (pool, &pool->transfer, &pool->transfer_waiters);
     1400        bd->waiters--;
     1401        break;
     1402
     1403      default:
     1404        rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
     1405    }
     1406  }
     1407
     1408  /*
     1409   * Buffer is linked to the LRU, modifed, or sync lists. Remove it from there.
     1410   */
     1411  rtems_chain_extract (&bd->link);
     1412
     1413  return bd;
     1414}
     1415
     1416/**
     1417 * Obtain block buffer. If specified block already cached (i.e. there's block
     1418 * in the _modified_, or _recently_used_), return address of appropriate buffer
     1419 * descriptor. If block is not cached, allocate new buffer and return it. Data
     1420 * shouldn't be read to the buffer from media; buffer may contains arbitrary
     1421 * data. This primitive may be blocked if there are no free buffer descriptors
     1422 * available and there are no unused non-modified (or synchronized with media)
     1423 * buffers available.
     1424 *
     1425 * @param device device number (constructed of major and minor device number)
     1426 * @param block linear media block number
     1427 * @param bd address of variable to store pointer to the buffer descriptor
     1428 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
     1429 *         or error code if error is occured)
    7771430 */
    7781431rtems_status_code
    779 rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size)
    780 {
    781     rtems_bdpool_id i;
    782     rtems_status_code rc;
    783 
    784     if (size <= 0)
    785         return RTEMS_INVALID_SIZE;
    786 
    787     rtems_bdbuf_ctx.npools = size;
    788 
    789     /*
    790      * Allocate memory for buffer pool descriptors
    791      */
    792     rtems_bdbuf_ctx.pool = calloc(size, sizeof(bdbuf_pool));
    793     if (rtems_bdbuf_ctx.pool == NULL)
    794     {
    795         return RTEMS_NO_MEMORY;
    796     }
    797 
    798     rtems_chain_initialize_empty(&rtems_bdbuf_ctx.mod);
    799 
    800     /* Initialize buffer pools and roll out if something failed */
    801     for (i = 0; i < size; i++)
    802     {
    803         rc = bdbuf_initialize_pool(conf_table + i, i);
    804         if (rc != RTEMS_SUCCESSFUL)
    805         {
    806              rtems_bdpool_id j;
    807              for (j = 0; j < i - 1; j++)
    808              {
    809                  bdbuf_release_pool(j);
    810              }
    811              return rc;
    812         }
    813     }
    814 
    815     /* Create buffer flush semaphore */
    816     rc = rtems_semaphore_create(
    817         rtems_build_name('B', 'F', 'L', 'U'), 0,
    818         RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
    819         RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0,
    820         &rtems_bdbuf_ctx.flush_sema);
    821     if (rc != RTEMS_SUCCESSFUL)
    822     {
    823         for (i = 0; i < size; i++)
    824             bdbuf_release_pool(i);
    825         free(rtems_bdbuf_ctx.pool);
    826         return rc;
    827     }
    828 
    829     /* Create and start swapout task */
    830     rc = rtems_task_create(
    831         rtems_build_name('B', 'S', 'W', 'P'),   
    832         ((swapout_task_priority > 0)
    833          ? swapout_task_priority
    834          : SWAPOUT_TASK_DEFAULT_PRIORITY),
    835         SWAPOUT_TASK_STACK_SIZE,
    836         RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
    837         RTEMS_DEFAULT_ATTRIBUTES,
    838         &rtems_bdbuf_ctx.swapout_task);
    839     if (rc != RTEMS_SUCCESSFUL)
    840     {
    841         rtems_semaphore_delete(rtems_bdbuf_ctx.flush_sema);
    842         for (i = 0; i < size; i++)
    843             bdbuf_release_pool(i);
    844         free(rtems_bdbuf_ctx.pool);
    845         return rc;
    846     }
    847 
    848     rc = rtems_task_start(rtems_bdbuf_ctx.swapout_task, bdbuf_swapout_task, 0);
    849     if (rc != RTEMS_SUCCESSFUL)
    850     {
    851         rtems_task_delete(rtems_bdbuf_ctx.swapout_task);
    852         rtems_semaphore_delete(rtems_bdbuf_ctx.flush_sema);
    853         for (i = 0; i < size; i++)
    854             bdbuf_release_pool(i);
    855         free(rtems_bdbuf_ctx.pool);
    856         return rc;
    857     }
    858 
    859     return RTEMS_SUCCESSFUL;
    860 }
    861 
    862 /* find_or_assign_buffer --
    863  *     Looks for buffer already assigned for this dev/block. If one is found
    864  *     obtain block buffer. If specified block already cached (i.e. there's
    865  *     block in the _modified_, or _recently_used_), return address
    866  *     of appropriate buffer descriptor and increment reference counter to 1.
    867  *     If block is not cached, allocate new buffer and return it. Data
    868  *     shouldn't be read to the buffer from media; buffer contains arbitrary
    869  *     data. This primitive may be blocked if there are no free buffer
    870  *     descriptors available and there are no unused non-modified (or
    871  *     synchronized with media) buffers available.
    872  *
    873  * PARAMETERS:
    874  *     device - device number (constructed of major and minor device number
    875  *     block  - linear media block number
    876  *     ret_buf - address of the variable to store address of found descriptor
    877  *
    878  * RETURNS:
    879  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    880  *     or error code if error is occured)
    881  *
    882  * SIDE EFFEECTS:
    883  *     bufget_sema may be obtained by this primitive
    884  *
    885  * NOTE:
    886  *     It is assumed that primitive invoked when thread preemption is disabled.
    887  */
    888 static rtems_status_code
    889 find_or_assign_buffer(disk_device *dd,
    890                       blkdev_bnum block,
    891                       bdbuf_buffer **ret_buf)
    892 {
    893     bdbuf_buffer *bd_buf;
    894     bdbuf_pool   *bd_pool;
    895     rtems_status_code rc;
    896     dev_t         device;
    897     ISR_Level     level;
    898 
    899     int blksize;
    900 
    901     device = dd->dev;
    902     bd_pool = rtems_bdbuf_ctx.pool + dd->pool;
    903     blksize = dd->block_size;
    904 
    905 again:
    906     /* Looking for buffer descriptor used for this dev/block. */
    907     bd_buf = avl_search(&bd_pool->tree, device, block);
    908 
    909     if (bd_buf == NULL)
    910     {
    911         /* Try to obtain semaphore without waiting first. It is the most
    912            frequent case when reasonable number of buffers configured. If
    913            it is failed, obtain semaphore blocking on it. In this case
    914            it should be checked that appropriate buffer hasn't been loaded
    915            by another thread, because this thread is preempted */
    916         rc = rtems_semaphore_obtain(bd_pool->bufget_sema, RTEMS_NO_WAIT, 0);
    917         if (rc == RTEMS_UNSATISFIED)
    918         {
    919             rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
    920                                         RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    921             bd_buf = avl_search(&bd_pool->tree, device, block);
    922             if (bd_buf != NULL)
    923                 rtems_semaphore_release(bd_pool->bufget_sema);
    924         }
    925     }
    926 
    927     if (bd_buf == NULL)
    928     {
    929         /* Assign new buffer descriptor */
    930         if (rtems_chain_is_empty(&bd_pool->free))
    931         {
    932             bd_buf = (bdbuf_buffer *)rtems_chain_get(&bd_pool->lru);
    933             if (bd_buf != NULL)
    934             {
    935                 int avl_result;
    936                 avl_result = avl_remove(&bd_pool->tree, bd_buf);
    937                 if (avl_result != 0)
    938                 {
    939                     rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
    940                     return RTEMS_INTERNAL_ERROR;
    941                 }
    942             }
    943         }
    944         else
    945         {
    946             bd_buf = (bdbuf_buffer *)rtems_chain_get(&(bd_pool->free));
    947         }
    948 
    949         if (bd_buf == NULL)
    950         {
    951             goto again;
    952         }
    953         else
    954         {
    955             bd_buf->dev = device;
    956             bd_buf->block = block;
    957 #ifdef AVL_GPL
    958             bd_buf->avl.link[0] = NULL;
    959             bd_buf->avl.link[1] = NULL;
    960 #else
    961             bd_buf->avl.left = NULL;
    962             bd_buf->avl.right = NULL;
     1432rtems_bdbuf_get (dev_t                device,
     1433                 rtems_blkdev_bnum    block,
     1434                 rtems_bdbuf_buffer** bdp)
     1435{
     1436  rtems_disk_device*  dd;
     1437  rtems_bdbuf_pool*   pool;
     1438  rtems_bdbuf_buffer* bd;
     1439
     1440  /*
     1441   * Do not hold the pool lock when obtaining the disk table.
     1442   */
     1443  dd = rtems_disk_obtain (device);
     1444  if (dd == NULL)
     1445    return RTEMS_INVALID_ID;
     1446
     1447  if (block >= dd->size)
     1448  {
     1449    rtems_disk_release (dd);
     1450    return RTEMS_INVALID_NUMBER;
     1451  }
     1452
     1453  block += dd->start;
     1454
     1455  pool = rtems_bdbuf_get_pool (dd->phys_dev->pool);
     1456 
     1457  rtems_disk_release(dd);
     1458
     1459  rtems_bdbuf_lock_pool (pool);
     1460
     1461#if RTEMS_BDBUF_TRACE
     1462  rtems_bdbuf_printf ("get: %d (dev = %08x)\n", block, device);
    9631463#endif
    964             bd_buf->use_count = 1;
    965             bd_buf->modified = bd_buf->actual = bd_buf->in_progress = FALSE;
    966             bd_buf->status = RTEMS_SUCCESSFUL;
    967 
    968             if (avl_insert(&bd_pool->tree, bd_buf) != 0)
    969             {
    970                 rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
    971                 return RTEMS_INTERNAL_ERROR;
    972             }
    973 
    974             *ret_buf = bd_buf;
    975 
    976             return RTEMS_SUCCESSFUL;
    977         }
    978     }
    979     else
    980     {
    981         /* Buffer descriptor already assigned for this dev/block */
    982         if (bd_buf->use_count == 0)
    983         {
    984             /* If we are removing from lru list, obtain the bufget_sema
    985              * first. If we are removing from mod list, obtain flush sema.
    986              * It should be obtained without blocking because we know
    987              * that our buffer descriptor is in the list. */
    988             if (bd_buf->modified)
    989             {
    990                 rc = rtems_semaphore_obtain(rtems_bdbuf_ctx.flush_sema,
    991                                             RTEMS_NO_WAIT, 0);
    992             }
    993             else
    994             {
    995                 rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
    996                                             RTEMS_NO_WAIT, 0);
    997             }
    998             /* It is possible that we couldn't obtain flush or bufget sema
    999              * although buffer in the appropriate chain is available:
    1000              * semaphore may be released to swapout task, but this task
    1001              * actually did not start to process it. */
    1002             if (rc == RTEMS_UNSATISFIED)
    1003                 rc = RTEMS_SUCCESSFUL;
    1004             if (rc != RTEMS_SUCCESSFUL)
    1005             {
    1006                 rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
    1007                 return RTEMS_INTERNAL_ERROR;
    1008             }
    1009 
    1010             /* Buffer descriptor is linked to the lru or mod chain. Remove
    1011                it from there. */
    1012             rtems_chain_extract(&bd_buf->link);
    1013         }
    1014         bd_buf->use_count++;
    1015         while (bd_buf->in_progress != 0)
    1016         {
    1017             rtems_interrupt_disable(level);
    1018             _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1019                               WATCHDOG_NO_TIMEOUT, level);
    1020         }
    1021 
    1022         *ret_buf = bd_buf;
    1023         return RTEMS_SUCCESSFUL;
    1024     }
    1025 }
    1026 
    1027 /* rtems_bdbuf_get --
    1028  *     Obtain block buffer. If specified block already cached (i.e. there's
    1029  *     block in the _modified_, or _recently_used_), return address
    1030  *     of appropriate buffer descriptor and increment reference counter to 1.
    1031  *     If block is not cached, allocate new buffer and return it. Data
    1032  *     shouldn't be read to the buffer from media; buffer may contains
    1033  *     arbitrary data. This primitive may be blocked if there are no free
    1034  *     buffer descriptors available and there are no unused non-modified
    1035  *     (or synchronized with media) buffers available.
    1036  *
    1037  * PARAMETERS:
    1038  *     device - device number (constructed of major and minor device number)
    1039  *     block  - linear media block number
    1040  *     bd     - address of variable to store pointer to the buffer descriptor
    1041  *
    1042  * RETURNS:
    1043  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1044  *     or error code if error is occured)
    1045  *
    1046  * SIDE EFFECTS:
    1047  *     bufget_sema semaphore obtained by this primitive.
    1048  */
    1049 rtems_status_code
    1050 rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bd)
    1051 {
    1052     rtems_status_code rc;
    1053     disk_device *dd;
    1054     disk_device *pdd;
    1055     preemption_key key;
    1056 
    1057     /*
    1058      * Convert logical dev/block to physical one
    1059      */
    1060     dd = rtems_disk_lookup(device);
    1061     if (dd == NULL)
    1062         return RTEMS_INVALID_ID;
    1063 
    1064     if (block >= dd->size)
    1065     {
    1066         rtems_disk_release(dd);
    1067         return RTEMS_INVALID_NUMBER;
    1068     }
    1069 
    1070     pdd = dd->phys_dev;
    1071     block += dd->start;
    1072     rtems_disk_release(dd);
    1073 
    1074     DISABLE_PREEMPTION(key);
    1075     rc = find_or_assign_buffer(pdd, block, bd);
    1076     ENABLE_PREEMPTION(key);
    1077 
    1078     if (rc != RTEMS_SUCCESSFUL)
    1079         return rc;
    1080 
    1081     return RTEMS_SUCCESSFUL;
    1082 }
    1083 
    1084 /* bdbuf_initialize_transfer_sema --
    1085  *     Initialize transfer_sema mutex semaphore associated with buffer
    1086  *     descriptor.
    1087  */
    1088 static inline void
    1089 bdbuf_initialize_transfer_sema(bdbuf_buffer *bd_buf)
    1090 {
    1091     CORE_mutex_Attributes mutex_attr;
    1092     mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_BLOCKS;
    1093     mutex_attr.only_owner_release = FALSE;
    1094     mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO;
    1095     mutex_attr.priority_ceiling = 0;
    1096 
    1097     _CORE_mutex_Initialize(&bd_buf->transfer_sema,
    1098                            &mutex_attr, CORE_MUTEX_LOCKED);
    1099 }
    1100 
    1101 /* bdbuf_write_transfer_done --
     1464
     1465  bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, block, FALSE);
     1466
     1467  if (bd->state == RTEMS_BDBUF_STATE_MODIFIED)
     1468    bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED;
     1469  else
     1470    bd->state = RTEMS_BDBUF_STATE_ACCESS;
     1471 
     1472  rtems_bdbuf_unlock_pool (pool);
     1473
     1474  *bdp = bd;
     1475 
     1476  return RTEMS_SUCCESSFUL;
     1477}
     1478
     1479/* bdbuf_read_transfer_done --
    11021480 *     Callout function. Invoked by block device driver when data transfer
    1103  *     to device (write) is completed. This function may be invoked from
     1481 *     from device (read) is completed. This function may be invoked from
    11041482 *     interrupt handler.
    11051483 *
     
    11151493 */
    11161494static void
    1117 bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error)
    1118 {
    1119     int i;
    1120     write_tfer_done_arg_t *wtd_arg = arg;
    1121     blkdev_request *req = wtd_arg->req;
    1122     bdbuf_buffer **bd_buf_write_store = wtd_arg->write_store;
    1123     bdbuf_buffer *bd_buf;
    1124     for (i = 0;i < req->count;i++) {
    1125       bd_buf = bd_buf_write_store[i];
    1126       bd_buf->status = status;
    1127       bd_buf->error = RTEMS_IO_ERROR;
     1495rtems_bdbuf_read_done (void* arg, rtems_status_code status, int error)
     1496{
     1497  rtems_blkdev_request* req = (rtems_blkdev_request*) arg;
     1498
     1499  req->error = error;
     1500  req->status = status;
     1501
     1502  rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC);
     1503}
     1504
     1505/**
     1506 * Read a block into memory. If the block is not is the cache it is read into
     1507 * memory. The caller is blocked until the block is read and placed into the
     1508 * cache.
     1509 *
     1510 * @param device The device number (consists of major and minor device number)
     1511 * @param block Linear media block number
     1512 * @param bd Pointer to the buffer BD address.
     1513 * @retval RTEMS_SUCCESSFUL Operation completed successfully.
     1514 * @return rtems_status_code An error code. Buffer still passed to caller.
     1515 */
     1516
     1517rtems_status_code
     1518rtems_bdbuf_read (dev_t                device,
     1519                  rtems_blkdev_bnum    block,
     1520                  rtems_bdbuf_buffer** bdp)
     1521{
     1522  rtems_disk_device*    dd;
     1523  rtems_bdbuf_pool*     pool;
     1524  rtems_bdbuf_buffer*   bd = NULL;
     1525  int                   read_ahead_count;
     1526  rtems_blkdev_request* req;
     1527 
     1528  /*
     1529   * @todo This type of request structure is wrong and should be removed.
     1530   */
     1531#define bdbuf_alloc(size) __builtin_alloca (size)
     1532
     1533  req = bdbuf_alloc (sizeof (rtems_blkdev_request) +
     1534                     (sizeof ( rtems_blkdev_sg_buffer) *
     1535                      rtems_bdbuf_configuration.max_read_ahead_blocks));
     1536
     1537  /*
     1538   * Do not hold the pool lock when obtaining the disk table.
     1539   */
     1540  dd = rtems_disk_obtain (device);
     1541  if (dd == NULL)
     1542    return RTEMS_INVALID_ID;
     1543
     1544  block += dd->start;
     1545 
     1546#if RTEMS_BDBUF_TRACE
     1547  rtems_bdbuf_printf ("read: %d (dev = %08x)\n", block, device);
     1548#endif
     1549 
     1550  if (block >= dd->size)
     1551  {
     1552    rtems_disk_release(dd);
     1553    return RTEMS_INVALID_NUMBER;
     1554  }
     1555
     1556  req->count = 0;
     1557  req->bufnum = 0;
     1558
     1559  /*
     1560   * Read the block plus the required number of blocks ahead. The number of
     1561   * blocks to read ahead is configured by the user and limited by the size of
     1562   * the disk or reaching a read ahead block that is also cached.
     1563   *
     1564   * Limit the blocks read by the size of the disk.
     1565   */
     1566  if ((rtems_bdbuf_configuration.max_read_ahead_blocks + block) < dd->size)
     1567    read_ahead_count = rtems_bdbuf_configuration.max_read_ahead_blocks;
     1568  else
     1569    read_ahead_count = dd->size - block;
     1570
     1571  pool = rtems_bdbuf_get_pool (dd->phys_dev->pool);
     1572
     1573  rtems_bdbuf_lock_pool (pool);
     1574
     1575  while (req->count < read_ahead_count)
     1576  {
     1577    /*
     1578     * Get the buffer for the requested block. If the block is cached then
     1579     * return it. If it is not cached transfer the block from the disk media
     1580     * into memory.
     1581     *
     1582     * We need to clean up any buffers allocated and not passed back to the
     1583     * caller.
     1584     */
     1585    bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool,
     1586                                 block + req->count,
     1587                                 req->count == 0 ? FALSE : TRUE);
     1588
     1589    /*
     1590     * Read ahead buffer is in the cache or none available. Read what we
     1591     * can.
     1592     */
     1593    if (!bd)
     1594      break;
     1595
     1596    /*
     1597     * Is the block we are interested in the cache ?
     1598     */
     1599    if ((bd->state == RTEMS_BDBUF_STATE_CACHED) ||
     1600        (bd->state == RTEMS_BDBUF_STATE_MODIFIED))
     1601      break;
     1602
     1603    bd->state = RTEMS_BDBUF_STATE_TRANSFER;
     1604    bd->error = 0;
     1605
     1606    /*
     1607     * @todo The use of these req blocks is not a great design.
     1608     *       The req is a struct with a single 'bufs' declared in the
     1609     *       req struct and the others are added in the outer level
     1610     *       struct. This relies on the structs joining as a single
     1611     *       array and that assumes the compiler packs the structs.
     1612     *       Why not just place on a list ? The BD has a node that
     1613     *       can be used.
     1614     */
     1615    req->bufs[req->count].user   = bd;
     1616    req->bufs[req->count].block  = bd->block;
     1617    req->bufs[req->count].length = dd->block_size;
     1618    req->bufs[req->count].buffer = bd->buffer;
     1619    req->count++;
     1620    req->bufnum++;
     1621  }
     1622
     1623  /*
     1624   * Transfer any requested buffers. If the request count is 0 we have found
     1625   * the block in the cache so return it.
     1626   */
     1627  if (req->count)
     1628  {
     1629    /*
     1630     * Unlock the pool. We have the buffer for the block and it will be in the
     1631     * access or transfer state. We may also have a number of read ahead blocks
     1632     * if we need to transfer data. At this point any other threads can gain
     1633     * access to the pool and if they are after any of the buffers we have they
     1634     * will block and be woken when the buffer is returned to the pool.
     1635     *
     1636     * If a transfer is needed the I/O operation will occur with pre-emption
     1637     * enabled and the pool unlocked. This is a change to the previous version
     1638     * of the bdbuf code.
     1639     */
     1640    int result;
     1641    int b;
     1642   
     1643    rtems_bdbuf_unlock_pool (pool);
     1644
     1645    req->req = RTEMS_BLKDEV_REQ_READ;
     1646    req->req_done = rtems_bdbuf_read_done;
     1647    req->done_arg = req;
     1648    req->io_task = rtems_task_self ();
     1649    req->status = RTEMS_RESOURCE_IN_USE;
     1650    req->error = 0;
     1651    req->start = dd->start;
     1652 
     1653    result = dd->ioctl (dd->phys_dev->dev, RTEMS_BLKIO_REQUEST, req);
     1654
     1655    /*
     1656     * Inspection of the DOS FS code shows the result from this function is
     1657     * handled and a buffer must be returned.
     1658     */
     1659    if (result < 0)
     1660    {
     1661      req->error = errno;
     1662      req->status = RTEMS_IO_ERROR;
     1663    }
     1664    else
     1665    {
     1666      rtems_status_code sc;
     1667      rtems_event_set   out;
     1668      sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC,
     1669                                RTEMS_EVENT_ALL | RTEMS_WAIT,
     1670                                0, &out);
     1671
     1672      if (sc != RTEMS_SUCCESSFUL)
     1673        rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
     1674    }
     1675
     1676    rtems_bdbuf_lock_pool (pool);
     1677
     1678    for (b = 1; b < req->count; b++)
     1679    {
     1680      bd = req->bufs[b].user;
     1681      bd->error = req->error;
     1682      bd->state = RTEMS_BDBUF_STATE_READ_AHEAD;
     1683      rtems_bdbuf_release (bd);
     1684    }
     1685
     1686    bd = req->bufs[0].user;
     1687  }
     1688
     1689  /*
     1690   * The data for this block is cached in the buffer.
     1691   */
     1692  if (bd->state == RTEMS_BDBUF_STATE_MODIFIED)
     1693    bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED;
     1694  else
     1695    bd->state = RTEMS_BDBUF_STATE_ACCESS;
     1696
     1697  rtems_bdbuf_unlock_pool (pool);
     1698  rtems_disk_release (dd);
     1699
     1700  *bdp = bd;
     1701
     1702  return RTEMS_SUCCESSFUL;
     1703}
     1704
     1705/**
     1706 * Release buffer that has been in use. The buffer could have been in the
     1707 * access state and so with a user of the cache or it was being transfered to
     1708 * or from the disk media and so with a driver. Wake any waiters. If no one is
     1709 * waiting and this is the only buffer on the LRU list see if anyone is
     1710 * waiting. Wake them if they are.
     1711 *
     1712 * If the buffer has been modified use the modified release call.
     1713 *
     1714 * @param bd The buffer to return to the pool.
     1715 * @retval RTEMS_SUCCESSFUL This operation always succeeds.
     1716 */
     1717
     1718rtems_status_code
     1719rtems_bdbuf_release (rtems_bdbuf_buffer* bd)
     1720{
     1721  rtems_bdbuf_pool* pool;
     1722
     1723  if (bd == NULL)
     1724    return RTEMS_INVALID_ADDRESS;
     1725
     1726  pool = rtems_bdbuf_get_pool (bd->pool);
     1727
     1728  rtems_bdbuf_lock_pool (pool);
     1729
     1730#if RTEMS_BDBUF_TRACE
     1731  rtems_bdbuf_printf ("release: %d\n", bd->block);
     1732#endif
     1733 
     1734  if (bd->state == RTEMS_BDBUF_STATE_ACCESS_MODIFIED)
     1735  {
     1736    rtems_bdbuf_append_modified (pool, bd);
     1737  }
     1738  else
     1739  {
     1740    /*
     1741     * If this is a read ahead buffer place the ready queue. Buffers are
     1742     * taken from here first. If we prepend then get from the queue the
     1743     * buffers furthermost from the read buffer will be used.
     1744     */
     1745    if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD)
     1746      rtems_chain_prepend (&pool->ready, &bd->link);
     1747    else
     1748    {
     1749      bd->state = RTEMS_BDBUF_STATE_CACHED;
     1750      rtems_chain_append (&pool->lru, &bd->link);
     1751    }
     1752  }
     1753 
     1754  /*
     1755   * If there are threads waiting to access the buffer wake them. Wake any
     1756   * waiters if this is the first buffer to placed back onto the queue.
     1757   */
     1758  if (bd->waiters)
     1759    rtems_bdbuf_wake (pool->access, &pool->access_waiters);
     1760  else
     1761  {
     1762    if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD)
     1763    {
     1764      if (rtems_chain_has_only_one_node (&pool->ready))
     1765        rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters);
     1766    }
     1767    else
     1768    {
     1769      if (rtems_chain_has_only_one_node (&pool->lru))
     1770        rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters);
     1771    }
     1772  }
     1773 
     1774  rtems_bdbuf_unlock_pool (pool);
     1775
     1776  return RTEMS_SUCCESSFUL;
     1777}
     1778
     1779/**
     1780 * Release buffer that has been in use and has been modified. The buffer could
     1781 * have been in the access state and so with a user of the cache or it was
     1782 * being transfered to or from the disk media and so with a driver. Wake any
     1783 * waiters. If no one is waiting and this is the only buffer on the LRU list
     1784 * see if anyone is waiting. Wake them if they are.
     1785 *
     1786 * If the buffer has been modified use the modified release call.
     1787 *
     1788 * @param bd The buffer to return to the pool.
     1789 * @retval RTEMS_SUCCESSFUL This operation always succeeds.
     1790 */
     1791
     1792rtems_status_code
     1793rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd)
     1794{
     1795  rtems_bdbuf_pool* pool;
     1796
     1797  if (bd == NULL)
     1798    return RTEMS_INVALID_ADDRESS;
     1799
     1800  pool = rtems_bdbuf_get_pool (bd->pool);
     1801
     1802  rtems_bdbuf_lock_pool (pool);
     1803
     1804#if RTEMS_BDBUF_TRACE
     1805  rtems_bdbuf_printf ("release modified: %d\n", bd->block);
     1806#endif
     1807
     1808  bd->hold_timer = rtems_bdbuf_configuration.swap_block_hold;
     1809 
     1810  rtems_bdbuf_append_modified (pool, bd);
     1811
     1812  if (bd->waiters)
     1813    rtems_bdbuf_wake (pool->access, &pool->access_waiters);
     1814 
     1815  rtems_bdbuf_unlock_pool (pool);
     1816
     1817  return RTEMS_SUCCESSFUL;
     1818}
     1819
     1820/**
     1821 * Wait until specified buffer synchronized with disk. Invoked on exchanges
     1822 * critical for data consistency on the media. The buffer is placed on the sync
     1823 * list and the swapper is woken. No sync lock is taken as the buffers on the
     1824 * sync list are taken first and passed to the driver before buffers on the
     1825 * modified list.
     1826 *
     1827 * @note This code does not lock the sync mutex and stop additions to the
     1828 *       modified queue. This means the buffer could be written and then
     1829 *       returned to the modified list but will not happen as the buffer's
     1830 *       state is sync.
     1831 *
     1832 * @param bd Pointer to the bdbuf_buffer structure previously obtained using
     1833 *           get/read primitive.
     1834 * @retval RTEMS_SUCCESSFUL Always returned.
     1835 */
     1836
     1837rtems_status_code
     1838rtems_bdbuf_sync (rtems_bdbuf_buffer* bd)
     1839{
     1840  rtems_bdbuf_pool* pool;
     1841  boolean           available;
     1842
     1843#if RTEMS_BDBUF_TRACE
     1844  rtems_bdbuf_printf ("sync: %d\n", bd->block);
     1845#endif
     1846 
     1847  if (bd == NULL)
     1848    return RTEMS_INVALID_ADDRESS;
     1849
     1850  pool = rtems_bdbuf_get_pool (bd->pool);
     1851
     1852  rtems_bdbuf_lock_pool (pool);
     1853
     1854  bd->state = RTEMS_BDBUF_STATE_SYNC;
     1855
     1856  rtems_chain_append (&pool->sync, &bd->link);
     1857
     1858  rtems_bdbuf_wake_swapper ();
     1859
     1860  available = FALSE;
     1861  while (!available)
     1862  {
     1863    switch (bd->state)
     1864    {
     1865      case RTEMS_BDBUF_STATE_CACHED:
     1866      case RTEMS_BDBUF_STATE_READ_AHEAD:
     1867      case RTEMS_BDBUF_STATE_MODIFIED:
     1868      case RTEMS_BDBUF_STATE_ACCESS:
     1869      case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
     1870        available = TRUE;
     1871        break;
     1872
     1873      case RTEMS_BDBUF_STATE_SYNC:
     1874      case RTEMS_BDBUF_STATE_TRANSFER:
     1875        bd->waiters++;
     1876        rtems_bdbuf_wait (pool, &pool->transfer, &pool->transfer_waiters);
     1877        bd->waiters--;
     1878        break;
     1879
     1880      default:
     1881        rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
     1882    }
     1883  }
     1884
     1885  rtems_bdbuf_unlock_pool (pool);
     1886 
     1887  return RTEMS_SUCCESSFUL;
     1888}
     1889
     1890/* rtems_bdbuf_syncdev --
     1891 *     Synchronize with disk all buffers containing the blocks belonging to
     1892 *     specified device.
     1893 *
     1894 * PARAMETERS:
     1895 *     dev - block device number
     1896 *
     1897 * RETURNS:
     1898 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
     1899 *     or error code if error is occured)
     1900 */
     1901rtems_status_code
     1902rtems_bdbuf_syncdev (dev_t dev)
     1903{
     1904  rtems_disk_device*  dd;
     1905  rtems_bdbuf_pool*   pool;
     1906  rtems_status_code   sc;
     1907  rtems_event_set     out;
     1908
     1909#if RTEMS_BDBUF_TRACE
     1910  rtems_bdbuf_printf ("syncdev: %08x\n", dev);
     1911#endif
     1912
     1913  /*
     1914   * Do not hold the pool lock when obtaining the disk table.
     1915   */
     1916  dd = rtems_disk_obtain (dev);
     1917  if (dd == NULL)
     1918    return RTEMS_INVALID_ID;
     1919
     1920  pool = rtems_bdbuf_get_pool (dd->pool);
     1921
     1922  /*
     1923   * Take the sync lock before locking the pool. Once we have the sync lock
     1924   * we can lock the pool. If another thread has the sync lock it will cause
     1925   * this thread to block until it owns the sync lock then it can own the
     1926   * pool. The sync lock can only be obtained with the pool unlocked.
     1927   */
     1928 
     1929  rtems_bdbuf_lock_sync (pool);
     1930  rtems_bdbuf_lock_pool (pool); 
     1931
     1932  pool->sync_active    = TRUE;
     1933  pool->sync_requester = rtems_task_self ();
     1934  pool->sync_device    = dev;
     1935 
     1936  rtems_bdbuf_wake_swapper ();
     1937  rtems_bdbuf_unlock_pool (pool);
     1938 
     1939  sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC,
     1940                            RTEMS_EVENT_ALL | RTEMS_WAIT,
     1941                            0, &out);
     1942
     1943  if (sc != RTEMS_SUCCESSFUL)
     1944    rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
    11281945     
    1129       bd_buf->in_progress = FALSE;
    1130       _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
    1131       _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1132                         CORE_MUTEX_STATUS_SUCCESSFUL);
    1133     }
    1134 }
    1135 
    1136 /* bdbuf_read_transfer_done --
     1946  rtems_bdbuf_lock_pool (pool);
     1947
     1948  pool->sync_active = FALSE;
     1949
     1950  rtems_bdbuf_unlock_sync (pool);
     1951  rtems_bdbuf_unlock_pool (pool);
     1952 
     1953  return rtems_disk_release(dd);
     1954}
     1955
     1956/* bdbuf_write_transfer_done --
    11371957 *     Callout function. Invoked by block device driver when data transfer
    1138  *     from device (read) is completed. This function may be invoked from
     1958 *     to device (write) is completed. This function may be invoked from
    11391959 *     interrupt handler.
    11401960 *
     
    11501970 */
    11511971static void
    1152 bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error)
    1153 {
    1154 #if defined(READ_MULTIPLE) 
    1155  
    1156   read_ahead_bd_buf_group *bd_buf_group = arg;
    1157   bdbuf_buffer *bd_buf;
    1158   int i;
    1159   for (i = 0;i < bd_buf_group->cnt;i++) {
    1160     bd_buf = bd_buf_group->bd_bufs[i];
    1161 
    1162     bd_buf->status = status;
    1163     bd_buf->error = RTEMS_IO_ERROR;
    1164     _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
    1165     _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1166                       CORE_MUTEX_STATUS_SUCCESSFUL);
    1167   }
    1168 #else
    1169     bdbuf_buffer *bd_buf = arg;
    1170     bd_buf->status = status;
    1171     bd_buf->error = RTEMS_IO_ERROR;
    1172     _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
    1173     _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1174                       CORE_MUTEX_STATUS_SUCCESSFUL);
    1175 #endif
    1176 }
    1177 
    1178 /* rtems_bdbuf_read --
    1179  *     (Similar to the rtems_bdbuf_get, except reading data from media)
    1180  *     Obtain block buffer. If specified block already cached, return address
    1181  *     of appropriate buffer and increment reference counter to 1. If block is
    1182  *     not cached, allocate new buffer and read data to it from the media.
    1183  *     This primitive may be blocked on waiting until data to be read from
    1184  *     media, if there are no free buffer descriptors available and there are
    1185  *     no unused non-modified (or synchronized with media) buffers available.
    1186  *
    1187  * PARAMETERS:
    1188  *     device - device number (consists of major and minor device number)
    1189  *     block  - linear media block number
    1190  *     bd     - address of variable to store pointer to the buffer descriptor
    1191  *
    1192  * RETURNS:
    1193  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1194  *     or error code if error is occured)
    1195  *
    1196  * SIDE EFFECTS:
    1197  *     bufget_sema and transfer_sema semaphores obtained by this primitive.
    1198  */
    1199 #if !defined(READ_MULTIPLE)
    1200 rtems_status_code
    1201 rtems_bdbuf_read(dev_t device,
    1202                  blkdev_bnum block,
    1203                  bdbuf_buffer **bd)
    1204 {
    1205     preemption_key key;
    1206     ISR_Level level;
    1207 
    1208     bdbuf_buffer *bd_buf;
    1209     rtems_status_code rc;
    1210     int result;
    1211     disk_device *dd;
    1212     disk_device *pdd;
    1213     blkdev_request1 req;
    1214 
    1215     dd = rtems_disk_lookup(device);
    1216     if (dd == NULL)
    1217         return RTEMS_INVALID_ID;
    1218 
    1219     if (block >= dd->size)
    1220     {
    1221         rtems_disk_release(dd);
    1222         return RTEMS_INVALID_NUMBER;
    1223     }
    1224 
    1225     pdd = dd->phys_dev;
    1226     block += dd->start;
    1227 
    1228     DISABLE_PREEMPTION(key);
    1229     rc = find_or_assign_buffer(pdd, block, &bd_buf);
    1230 
    1231     if (rc != RTEMS_SUCCESSFUL)
    1232     {
    1233         ENABLE_PREEMPTION(key);
    1234         rtems_disk_release(dd);
    1235         return rc;
    1236     }
    1237 
    1238     if (!bd_buf->actual)
    1239     {
    1240         bd_buf->in_progress = 1;
    1241 
    1242         req.req.req = BLKDEV_REQ_READ;
    1243         req.req.req_done = bdbuf_read_transfer_done;
    1244         req.req.done_arg = bd_buf;
    1245         req.req.start = block;
    1246         req.req.count = 1;
    1247         req.req.bufnum = 1;
    1248         req.req.bufs[0].length = dd->block_size;
    1249         req.req.bufs[0].buffer = bd_buf->buffer;
    1250 
    1251         bdbuf_initialize_transfer_sema(bd_buf);
    1252         result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req);
    1253         if (result == -1)
     1972rtems_bdbuf_write_done(void *arg, rtems_status_code status, int error)
     1973{
     1974  rtems_blkdev_request* req = (rtems_blkdev_request*) arg;
     1975
     1976  req->error = error;
     1977  req->status = status;
     1978
     1979  rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC);
     1980}
     1981
     1982/**
     1983 * Process the modified list of buffers. We can have a sync or modified
     1984 * list that needs to be handled.
     1985 */
     1986static void
     1987rtems_bdbuf_swapout_modified_processing (rtems_bdpool_id      pid,
     1988                                         dev_t*               dev,
     1989                                         rtems_chain_control* chain,
     1990                                         rtems_chain_control* transfer,
     1991                                         boolean              sync_active,
     1992                                         boolean              update_timers,
     1993                                         uint32_t             timer_delta)
     1994{
     1995  if (!rtems_chain_is_empty (chain))
     1996  {
     1997    rtems_chain_node* node = rtems_chain_head (chain);
     1998    node = node->next;
     1999
     2000    while (!rtems_chain_is_tail (chain, node))
     2001    {
     2002      rtems_bdbuf_buffer* bd = (rtems_bdbuf_buffer*) node;
     2003   
     2004      if (bd->pool == pid)
     2005      {
     2006        /*
     2007         * Check if the buffer's hold timer has reached 0. If a sync
     2008         * is active force all the timers to 0.
     2009         *
     2010         * @note Lots of sync requests will skew this timer. It should
     2011         *       be based on TOD to be accurate. Does it matter ?
     2012         */
     2013        if (sync_active)
     2014          bd->hold_timer = 0;
     2015 
     2016        if (bd->hold_timer)
    12542017        {
    1255             bd_buf->status = RTEMS_IO_ERROR;
    1256             bd_buf->error = errno;
    1257             bd_buf->actual = FALSE;
     2018          if (update_timers)
     2019          {
     2020            if (bd->hold_timer > timer_delta)
     2021              bd->hold_timer -= timer_delta;
     2022            else
     2023              bd->hold_timer = 0;
     2024          }
     2025
     2026          if (bd->hold_timer)
     2027          {
     2028            node = node->next;
     2029            continue;
     2030          }
     2031        }
     2032
     2033        /*
     2034         * This assumes we can set dev_t to -1 which is just an
     2035         * assumption. Cannot use the transfer list being empty
     2036         * the sync dev calls sets the dev to use.
     2037         */
     2038        if (*dev == -1)
     2039          *dev = bd->dev;
     2040
     2041        if (bd->dev == *dev)
     2042        {
     2043          rtems_chain_node* next_node = node->next;
     2044          rtems_chain_extract (node);
     2045          rtems_chain_append (transfer, node);
     2046          node = next_node;
     2047          bd->state = RTEMS_BDBUF_STATE_TRANSFER;
    12582048        }
    12592049        else
    12602050        {
    1261             rtems_interrupt_disable(level);
    1262             _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1263                               WATCHDOG_NO_TIMEOUT, level);
    1264             bd_buf->actual = TRUE;
     2051          node = node->next;
    12652052        }
    1266         bd_buf->in_progress = FALSE;
    1267     }
    1268     rtems_disk_release(dd);
    1269 
    1270     ENABLE_PREEMPTION(key);
    1271 
    1272     *bd = bd_buf;
    1273            
    1274     return RTEMS_SUCCESSFUL;
    1275 }
    1276 #else /* READ_MULTIPLE */
    1277 rtems_status_code
    1278 rtems_bdbuf_read(dev_t device,
    1279                  blkdev_bnum block,
    1280                  bdbuf_buffer **bd)
    1281 {
    1282     preemption_key key;
    1283     ISR_Level level;
    1284 
    1285     bdbuf_buffer *bd_buf,*first_bd_buf;
    1286     rtems_status_code rc;
    1287     int result;
    1288     disk_device *dd;
    1289     disk_device *pdd;
    1290     blkdev_request_read_ahead req;
    1291     read_ahead_bd_buf_group bd_buf_group;
    1292     boolean find_more_buffers;
    1293     int i;
    1294 
    1295     dd = rtems_disk_lookup(device);
     2053      }
     2054    }
     2055  }
     2056}
     2057
     2058/**
     2059 * Process the pool.
     2060 */
     2061static boolean
     2062rtems_bdbuf_swapout_pool_processing (rtems_bdpool_id       pid,
     2063                                     unsigned long         timer_delta,
     2064                                     boolean               update_timers,
     2065                                     rtems_blkdev_request* write_req)
     2066{
     2067  rtems_bdbuf_pool*   pool = rtems_bdbuf_get_pool (pid);
     2068  rtems_chain_control transfer;
     2069  dev_t               dev = -1;
     2070  rtems_disk_device*  dd;
     2071  boolean             result = TRUE;
     2072
     2073  rtems_chain_initialize_empty (&transfer);
     2074   
     2075  rtems_bdbuf_lock_pool (pool);
     2076
     2077  if (pool->sync_active)
     2078    dev = pool->sync_device;
     2079
     2080#if 1
     2081  /*
     2082   * If we have any buffers in the sync queue move then to the
     2083   * modified list. The first sync buffer will select the
     2084   * device we use.
     2085   */
     2086  rtems_bdbuf_swapout_modified_processing (pid, &dev,
     2087                                           &pool->sync, &transfer,
     2088                                           TRUE, FALSE,
     2089                                           timer_delta);
     2090
     2091  /*
     2092   * Process the pool's modified list.
     2093   */
     2094  rtems_bdbuf_swapout_modified_processing (pid, &dev,
     2095                                           &pool->modified, &transfer,
     2096                                           pool->sync_active,
     2097                                           update_timers,
     2098                                           timer_delta);
     2099
     2100  /*
     2101   * We have all the buffers that have been modified for this device so
     2102   * the pool can be unlocked because the state is set to TRANSFER.
     2103   */
     2104#endif
     2105  rtems_bdbuf_unlock_pool (pool);
     2106
     2107  /*
     2108   * If there are buffers to transfer to the media tranfer them.
     2109   */
     2110  if (rtems_chain_is_empty (&transfer))
     2111    result = FALSE;
     2112  else
     2113  {
     2114    /*
     2115     * Obtain the disk device. Release the pool mutex to avoid a dead
     2116     * lock.
     2117     */
     2118    dd = rtems_disk_obtain (dev);
    12962119    if (dd == NULL)
    1297         return RTEMS_INVALID_ID;
    1298      
    1299     if (block >= dd->size)
    1300     {
    1301         rtems_disk_release(dd);
    1302         return RTEMS_INVALID_NUMBER;
    1303     }
    1304    
    1305     pdd = dd->phys_dev;
    1306     block += dd->start;
    1307 
    1308     DISABLE_PREEMPTION(key);
    1309     rc = find_or_assign_buffer(pdd, block, &first_bd_buf);
    1310 
    1311     if (rc != RTEMS_SUCCESSFUL)
    1312     {
    1313         ENABLE_PREEMPTION(key);
    1314         rtems_disk_release(dd);
    1315         return rc;
    1316     }
    1317     if (!first_bd_buf->actual)
    1318     {
    1319 
    1320         bd_buf_group.bd_bufs[0] = first_bd_buf;
    1321         bd_buf_group.cnt = 1;
    1322 
    1323         first_bd_buf->in_progress = TRUE;
    1324 
    1325         req.req.req = BLKDEV_REQ_READ;
    1326         req.req.req_done = bdbuf_read_transfer_done;
    1327         req.req.done_arg = &bd_buf_group;
    1328         req.req.start = block;
    1329         req.req.count = 1;
    1330         req.req.bufnum = 1;
    1331         req.req.bufs[0].length = dd->block_size;
    1332         req.req.bufs[0].buffer = first_bd_buf->buffer;
     2120      result = FALSE;
     2121    else
     2122    {
     2123      /*
     2124       * The last block number used when the driver only supports
     2125       * continuous blocks in a single request.
     2126       */
     2127      uint32_t last_block = 0;
     2128     
     2129      /*
     2130       * Take as many buffers are configured and pass to the driver. Note,
     2131       * the API to the drivers has the array of buffers and if a chain was
     2132       * passed we could have just passed the list. If the driver API is
     2133       * updated it should be possible to make this change with little effect
     2134       * in this code. The array that is passed is broken in design and
     2135       * should be removed. Merging to members of a struct into the first
     2136       * member is trouble waiting to happen.
     2137       */
     2138
     2139      write_req->status = RTEMS_RESOURCE_IN_USE;
     2140      write_req->start = dd->start;
     2141      write_req->error = 0;
     2142      write_req->count = 0;
     2143      write_req->bufnum = 0;
     2144
     2145      while (!rtems_chain_is_empty (&transfer))
     2146      {
     2147        rtems_bdbuf_buffer* bd =
     2148          (rtems_bdbuf_buffer*) rtems_chain_get (&transfer);
     2149
     2150        boolean write = FALSE;
    13332151       
    1334         bdbuf_initialize_transfer_sema(first_bd_buf);
    1335         /*
    1336          * FIXME: check for following blocks to be:
    1337          *   - still in range of partition size
    1338          *   - not yet assigned
    1339          *   - buffer available
    1340          * allocate for read call, if possible
    1341          */
    1342         find_more_buffers = TRUE;
    1343         while (find_more_buffers) {       
    1344           block++;
    1345           /*
    1346            * still bd_buf_group entries free and
    1347            * still in range of this disk?
    1348            */
    1349           if ((bd_buf_group.cnt >= READ_AHEAD_MAX_BLK_CNT) ||
    1350               (block >= dd->size)) {
    1351             find_more_buffers = FALSE;
    1352           }
    1353           if (find_more_buffers) {
    1354             rc = find_or_assign_buffer(pdd, block, &bd_buf);
    1355             if (rc != RTEMS_SUCCESSFUL) {
    1356               find_more_buffers = FALSE;
    1357             }     
    1358             else if (bd_buf->actual) {
    1359               find_more_buffers = FALSE;
    1360           bdbuf_release(bd_buf);
    1361             }     
    1362           }
    1363           if (find_more_buffers) {
    1364             bdbuf_initialize_transfer_sema(bd_buf);
    1365             bd_buf->in_progress = TRUE;
    1366 
    1367             req.req.bufs[req.req.count].length = dd->block_size;
    1368             req.req.bufs[req.req.count].buffer = bd_buf->buffer;
    1369             req.req.count++;
    1370             req.req.bufnum++;
    1371             bd_buf_group.bd_bufs[bd_buf_group.cnt] = bd_buf;
    1372             bd_buf_group.cnt++;
    1373           }
    1374         }           
    1375 
    1376         /* do the actual read call here
    1377          */
    1378         result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req);
    1379 
    1380         /*
    1381          * cleanup:
    1382          * wait, until all bd_bufs are processed
    1383          * set status in all bd_bufs
    1384          */
    1385         for (i = 0;i < bd_buf_group.cnt;i++) {
    1386           bd_buf = bd_buf_group.bd_bufs[i];
    1387           if (result == -1)
    1388             {
    1389               bd_buf->status = RTEMS_IO_ERROR;
    1390               bd_buf->error = errno;
    1391               bd_buf->actual = FALSE;
    1392             }
    1393           else
    1394             {
    1395               rtems_interrupt_disable(level);
    1396               _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1397                                 WATCHDOG_NO_TIMEOUT, level);
    1398               bd_buf->actual = TRUE;
    1399             }   
    1400           bd_buf->in_progress = FALSE;
    1401           /* release any pre-read buffers */
    1402           if (i > 0) {
    1403             bdbuf_release(bd_buf);
    1404           }
    1405         }
    1406     }
    1407     rtems_disk_release(dd);
    1408    
    1409     ENABLE_PREEMPTION(key);
    1410 
    1411     *bd = first_bd_buf;
    1412            
    1413     return RTEMS_SUCCESSFUL;
    1414 }
    1415 #endif /* READ_MULTIPLE */
    1416 
    1417 
    1418 /* bdbuf_release --
    1419  *     Release buffer. Decrease buffer usage counter. If it is zero, further
    1420  *     processing depends on modified attribute. If buffer was modified, it
    1421  *     is inserted into mod chain and swapout task waken up. If buffer was
    1422  *     not modified, it is returned to the end of lru chain making it available
    1423  *     for further use.
    1424  *
    1425  * PARAMETERS:
    1426  *     bd_buf - pointer to the released buffer descriptor.
    1427  *
    1428  * RETURNS:
    1429  *     RTEMS_SUCCESSFUL if buffer released successfully, or error code if
    1430  *     error occured.
    1431  *
    1432  * NOTE:
    1433  *     This is internal function. It is assumed that task made non-preemptive
    1434  *     before its invocation.
    1435  */
    1436 static rtems_status_code
    1437 bdbuf_release(bdbuf_buffer *bd_buf)
    1438 {
    1439     bdbuf_pool *bd_pool;
    1440     rtems_status_code rc = RTEMS_SUCCESSFUL;
    1441 
    1442     if (bd_buf->use_count <= 0)
    1443         return RTEMS_INTERNAL_ERROR;
    1444 
    1445     bd_pool = rtems_bdbuf_ctx.pool + bd_buf->pool;
    1446 
    1447     bd_buf->use_count--;
    1448 
    1449     if (bd_buf->use_count == 0)
    1450     {
    1451         if (bd_buf->modified)
     2152        /*
     2153         * If the device only accepts sequential buffers and
     2154         * this is not the first buffer (the first is always
     2155         * sequential, and the buffer is not sequential then
     2156         * put the buffer back on the transfer chain and
     2157         * write the committed buffers.
     2158         */
     2159       
     2160        if ((dd->capabilities & RTEMS_BLKDEV_CAP_MULTISECTOR_CONT) &&
     2161            write_req->count &&
     2162            (bd->block != (last_block + 1)))
    14522163        {
    1453 
    1454             /* Buffer was modified. Insert buffer to the modified buffers
    1455              * list and initiate flushing. */
    1456             rtems_chain_append(&rtems_bdbuf_ctx.mod, &bd_buf->link);
    1457 
    1458             /* Release the flush_sema */
    1459             rc = rtems_semaphore_release(rtems_bdbuf_ctx.flush_sema);
     2164          rtems_chain_prepend (&transfer, &bd->link);
     2165          write = TRUE;
    14602166        }
    14612167        else
    14622168        {
    1463             /* Buffer was not modified. Add this descriptor to the
    1464              * end of lru chain and make it available for reuse. */
    1465             rtems_chain_append(&bd_pool->lru, &bd_buf->link);
    1466             rc = rtems_semaphore_release(bd_pool->bufget_sema);
     2169          write_req->bufs[write_req->count].user   = bd;
     2170          write_req->bufs[write_req->count].block  = bd->block;
     2171          write_req->bufs[write_req->count].length = dd->block_size;
     2172          write_req->bufs[write_req->count].buffer = bd->buffer;
     2173          write_req->count++;
     2174          write_req->bufnum++;
     2175          last_block = bd->block;
    14672176        }
    1468     }
    1469     return rc;
    1470 }
    1471 
    1472 
    1473 /* rtems_bdbuf_release --
    1474  *     Release buffer allocated before. This primitive decrease the
    1475  *     usage counter. If it is zero, further destiny of buffer depends on
    1476  *     'modified' status. If buffer was modified, it is placed to the end of
    1477  *     mod list and flush task waken up. If buffer was not modified,
    1478  *     it is placed to the end of lru list, and bufget_sema released, allowing
    1479  *     to reuse this buffer.
    1480  *
    1481  * PARAMETERS:
    1482  *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
    1483  *              get/read primitive.
    1484  *
    1485  * RETURNS:
    1486  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1487  *     or error code if error is occured)
    1488  *
    1489  * SIDE EFFECTS:
    1490  *     flush_sema and bufget_sema semaphores may be released by this primitive.
    1491  */
    1492 rtems_status_code
    1493 rtems_bdbuf_release(bdbuf_buffer *bd_buf)
    1494 {
    1495     preemption_key key;
    1496     rtems_status_code rc = RTEMS_SUCCESSFUL;
    1497 
    1498     if (bd_buf == NULL)
    1499         return RTEMS_INVALID_ADDRESS;
    1500 
    1501     DISABLE_PREEMPTION(key);
    1502 
    1503     rc = bdbuf_release(bd_buf);
    1504 
    1505     ENABLE_PREEMPTION(key);
    1506 
    1507     return rc;
    1508 }
    1509 
    1510 /* rtems_bdbuf_release_modified --
    1511  *     Release buffer allocated before, assuming that it is _modified_ by
    1512  *     it's owner. This primitive decrease usage counter for buffer, mark
    1513  *     buffer descriptor as modified. If usage counter is 0, insert it at
    1514  *     end of mod chain and release flush_sema semaphore to activate the
    1515  *     flush task.
    1516  *
    1517  * PARAMETERS:
    1518  *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
    1519  *              get/read primitive.
    1520  *
    1521  * RETURNS:
    1522  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1523  *     or error code if error is occured)
    1524  *
    1525  * SIDE EFFECTS:
    1526  *     flush_sema semaphore may be released by this primitive.
    1527  */
    1528 rtems_status_code
    1529 rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf)
    1530 {
    1531     preemption_key key;
    1532     rtems_status_code rc = RTEMS_SUCCESSFUL;
    1533 
    1534     if (bd_buf == NULL)
    1535         return RTEMS_INVALID_ADDRESS;
    1536 
    1537     DISABLE_PREEMPTION(key);
    1538 
    1539     if (!bd_buf->modified)
    1540     {
    1541         bdbuf_initialize_transfer_sema(bd_buf);
    1542     }
    1543     bd_buf->modified = TRUE;
    1544     bd_buf->actual = TRUE;
    1545     rc = bdbuf_release(bd_buf);
    1546 
    1547     ENABLE_PREEMPTION(key);
    1548 
    1549     return rc;
    1550 }
    1551 
    1552 /* rtems_bdbuf_sync --
    1553  *     Wait until specified buffer synchronized with disk. Invoked on exchanges
    1554  *     critical for data consistency on the media. This primitive mark owned
    1555  *     block as modified, decrease usage counter. If usage counter is 0,
    1556  *     block inserted to the mod chain and flush_sema semaphore released.
    1557  *     Finally, primitives blocked on transfer_sema semaphore.
    1558  *
    1559  * PARAMETERS:
    1560  *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
    1561  *              get/read primitive.
    1562  *
    1563  * RETURNS:
    1564  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1565  *     or error code if error is occured)
    1566  *
    1567  * SIDE EFFECTS:
    1568  *     Primitive may be blocked on transfer_sema semaphore.
    1569  */
    1570 rtems_status_code
    1571 rtems_bdbuf_sync(bdbuf_buffer *bd_buf)
    1572 {
    1573     preemption_key key;
    1574     ISR_Level level;
    1575     rtems_status_code rc = RTEMS_SUCCESSFUL;
    1576 
    1577     if (bd_buf == NULL)
    1578         return RTEMS_INVALID_ADDRESS;
    1579 
    1580     DISABLE_PREEMPTION(key);
    1581 
    1582     if (!bd_buf->modified)
    1583     {
    1584         bdbuf_initialize_transfer_sema(bd_buf);
    1585     }
    1586     bd_buf->modified = TRUE;
    1587     bd_buf->actual = TRUE;
    1588 
    1589     rc = bdbuf_release(bd_buf);
    1590 
    1591     if (rc == RTEMS_SUCCESSFUL)
    1592     {
    1593         rtems_interrupt_disable(level);
    1594         _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1595                           WATCHDOG_NO_TIMEOUT, level);
    1596     }
    1597 
    1598     ENABLE_PREEMPTION(key);
    1599 
    1600     return rc;
    1601 }
    1602 
    1603 /* rtems_bdbuf_syncdev --
    1604  *     Synchronize with disk all buffers containing the blocks belonging to
    1605  *     specified device.
    1606  *
    1607  * PARAMETERS:
    1608  *     dev - block device number
    1609  *
    1610  * RETURNS:
    1611  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1612  *     or error code if error is occured)
    1613  */
    1614 rtems_status_code
    1615 rtems_bdbuf_syncdev(dev_t dev)
    1616 {
    1617     preemption_key key;
    1618     ISR_Level level;
    1619 
    1620     bdbuf_buffer *bd_buf;
    1621     disk_device *dd;
    1622     bdbuf_pool  *pool;
    1623 
    1624     dd = rtems_disk_lookup(dev);
    1625     if (dd == NULL)
    1626         return RTEMS_INVALID_ID;
    1627 
    1628     pool = rtems_bdbuf_ctx.pool + dd->pool;
    1629 
    1630     DISABLE_PREEMPTION(key);
    1631     do {
    1632         bd_buf = avl_search_for_sync(&pool->tree, dd);
    1633         if (bd_buf != NULL /* && bd_buf->modified */)
     2177
     2178        /*
     2179         * Perform the transfer if there are no more buffers, or the
     2180         * transfer size has reached the configured max. value.
     2181         */
     2182
     2183        if (rtems_chain_is_empty (&transfer) ||
     2184            (write_req->count >= rtems_bdbuf_configuration.max_write_blocks))
     2185          write = TRUE;
     2186
     2187        if (write)
    16342188        {
    1635             rtems_interrupt_disable(level);
    1636             _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1637                               WATCHDOG_NO_TIMEOUT, level);
     2189          int result;
     2190          int b;
     2191
     2192          /*
     2193           * Perform the transfer. No pool locks, no preemption, only the
     2194           * disk device is being held.
     2195           */
     2196          result = dd->ioctl (dd->phys_dev->dev,
     2197                              RTEMS_BLKIO_REQUEST, write_req);
     2198
     2199          if (result < 0)
     2200          {
     2201            rtems_bdbuf_lock_pool (pool);
     2202             
     2203            for (b = 0; b < write_req->count; b++)
     2204            {
     2205              bd = write_req->bufs[b].user;
     2206              bd->state  = RTEMS_BDBUF_STATE_MODIFIED;
     2207              bd->error = errno;
     2208
     2209              /*
     2210               * Place back on the pools modified queue and try again.
     2211               *
     2212               * @warning Not sure this is the best option but I do
     2213               *          not know what else can be done.
     2214               */
     2215              rtems_chain_append (&pool->modified, &bd->link);
     2216            }
     2217          }
     2218          else
     2219          {
     2220            rtems_status_code sc = 0;
     2221            rtems_event_set   out;
     2222
     2223            sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC,
     2224                                      RTEMS_EVENT_ALL | RTEMS_WAIT,
     2225                                      0, &out);
     2226
     2227            if (sc != RTEMS_SUCCESSFUL)
     2228              rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
     2229
     2230            rtems_bdbuf_lock_pool (pool);
     2231
     2232            for (b = 0; b < write_req->count; b++)
     2233            {
     2234              bd = write_req->bufs[b].user;
     2235              bd->state = RTEMS_BDBUF_STATE_CACHED;
     2236              bd->error = 0;
     2237
     2238              rtems_chain_append (&pool->lru, &bd->link);
     2239             
     2240              if (bd->waiters)
     2241                rtems_bdbuf_wake (pool->transfer, &pool->transfer_waiters);
     2242              else
     2243              {
     2244                if (rtems_chain_has_only_one_node (&pool->lru))
     2245                  rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters);
     2246              }
     2247            }
     2248          }
     2249
     2250          rtems_bdbuf_unlock_pool (pool);
     2251
     2252          write_req->status = RTEMS_RESOURCE_IN_USE;
     2253          write_req->error = 0;
     2254          write_req->count = 0;
     2255          write_req->bufnum = 0;
    16382256        }
    1639     } while (bd_buf != NULL);
    1640     ENABLE_PREEMPTION(key);
    1641     return rtems_disk_release(dd);
    1642 }
    1643 
    1644 /* bdbuf_swapout_task --
    1645  *     Body of task which take care on flushing modified buffers to the
    1646  *     disk.
     2257      }
     2258         
     2259      rtems_disk_release (dd);
     2260    }
     2261  }
     2262
     2263  if (pool->sync_active)
     2264    rtems_event_send (pool->sync_requester, RTEMS_BDBUF_TRANSFER_SYNC);
     2265 
     2266  return result;
     2267}
     2268
     2269/**
     2270 * Body of task which take care on flushing modified buffers to the disk.
    16472271 */
    16482272static rtems_task
    1649 bdbuf_swapout_task(rtems_task_argument unused)
    1650 {
    1651     rtems_status_code rc;
    1652     int result;
    1653     int i;
    1654     ISR_Level level;
    1655     bdbuf_buffer *bd_buf;
    1656     bdbuf_buffer *nxt_bd_buf;
    1657     bdbuf_pool *bd_pool = NULL;
    1658     disk_device *dd = NULL;
    1659     struct {
    1660       blkdev_request   req;
    1661       blkdev_sg_buffer sg[SWAP_OUT_MAX_BLK_CNT];
    1662     } req;
    1663     write_tfer_done_arg_t write_tfer_done_arg;
     2273rtems_bdbuf_swapout_task (rtems_task_argument arg)
     2274{
     2275  rtems_bdbuf_context*  context = (rtems_bdbuf_context*) arg;
     2276  rtems_blkdev_request* write_req;
     2277  uint32_t              period_in_ticks;
     2278  const uint32_t        period_in_msecs = rtems_bdbuf_configuration.swapout_period;
     2279  uint32_t              timer_delta;
     2280  rtems_status_code     sc;
     2281
     2282  /*
     2283   * @note chrisj The rtems_blkdev_request and the array at the end is a hack.
     2284   * I am disappointment at finding code like this in RTEMS. The request should
     2285   * have been a rtems_chain_control. Simple, fast and less storage as the node
     2286   * is already part of the buffer structure.
     2287   */
     2288  write_req =
     2289    malloc (sizeof (rtems_blkdev_request) +
     2290            (rtems_bdbuf_configuration.max_write_blocks *
     2291             sizeof (rtems_blkdev_sg_buffer)));
     2292
     2293  if (!write_req)
     2294    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM);
     2295
     2296  write_req->req = RTEMS_BLKDEV_REQ_WRITE;
     2297  write_req->req_done = rtems_bdbuf_write_done;
     2298  write_req->done_arg = write_req;
     2299  write_req->io_task = rtems_task_self ();
     2300
     2301  period_in_ticks = TOD_MICROSECONDS_TO_TICKS (period_in_msecs * 1000);
     2302
     2303  /*
     2304   * This is temporary. Needs to be changed to use the real clock.
     2305   */
     2306  timer_delta = period_in_msecs;
     2307
     2308  while (context->swapout_enabled)
     2309  {
     2310    rtems_event_set out;
    16642311
    16652312    /*
    1666      * provide info needed for write_transfer_done function
     2313     * Only update the timers once in the processing cycle.
    16672314     */
    1668     write_tfer_done_arg.req         = (blkdev_request *)&req.req;
    1669     write_tfer_done_arg.write_store =  bd_buf_write_store;
    1670     nxt_bd_buf = NULL;
    1671     while (1)
    1672     {
    1673         req.req.req = BLKDEV_REQ_WRITE;
    1674         req.req.req_done = bdbuf_write_transfer_done;
    1675         req.req.done_arg = &write_tfer_done_arg;
    1676         req.req.count = 0;
    1677         req.req.bufnum = 0;
    1678         bd_buf = NULL;
    1679         do {
    1680           /*
    1681            * if a buffer was left over from last loop, then use this buffer
    1682            * otherwise fetch new buffer from chain.
    1683            * Wait for buffer, if this is the first one of the request,
    1684            * otherwise do not wait, if no buffer available
    1685            */
    1686           if (nxt_bd_buf == NULL) {
    1687             rc = rtems_semaphore_obtain(rtems_bdbuf_ctx.flush_sema,
    1688                                         (req.req.count == 0)
    1689                                         ? RTEMS_WAIT
    1690                                         : RTEMS_NO_WAIT,
    1691                                         0);
    1692             if (rc == RTEMS_SUCCESSFUL) {
    1693               nxt_bd_buf = (bdbuf_buffer *)rtems_chain_get(&rtems_bdbuf_ctx.mod);
    1694           if (nxt_bd_buf != NULL) {
    1695                 nxt_bd_buf->in_progress = TRUE;
    1696             /* IMD try: clear "modified" bit early             */
    1697             /* (and not in bdbuf_write_transfer_done) to allow */
    1698             /* another modification during write processing    */
    1699             nxt_bd_buf->modified    = FALSE;
    1700 
    1701                 nxt_bd_buf->use_count++;
    1702                   }
    1703             }
    1704             else if ((rc != RTEMS_UNSATISFIED) &&
    1705                      (rc != RTEMS_TIMEOUT)) {
    1706               rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT);
    1707             }
    1708           }
    1709           /*
    1710            * It is possible that flush_sema semaphore will be released, but
    1711            * buffer to be removed from mod chain before swapout task start
    1712            * its processing.
    1713            */
    1714           if ((req.req.count == 0)  || /* first bd_buf for this request */
    1715               ((nxt_bd_buf        != NULL)            &&
    1716                (nxt_bd_buf->dev   == bd_buf->dev)     && /* same device */
    1717                (nxt_bd_buf->block == bd_buf->block+1))) {/* next block  */
    1718             bd_buf     = nxt_bd_buf;
    1719             nxt_bd_buf = NULL;
    1720           }
    1721           else {
    1722             bd_buf = NULL;
    1723           }
    1724           /*
    1725            * here we have three possible states:
    1726            * bd_buf == NULL, nxt_bd_buf == NULL: no further block available
    1727            * bd_buf != NULL, nxt_bd_buf == NULL: append bd_buf to request
    1728            * bd_buf == NULL, nxt_bd_buf != NULL: nxt_bd_buf canot be appended
    1729            *                                     to current request, keep it
    1730            *                                     for next main loop
    1731            */
    1732           if (bd_buf != NULL) {
    1733             bd_pool = rtems_bdbuf_ctx.pool + bd_buf->pool;
    1734             if (req.req.count == 0) {
    1735               /*
    1736                * this is the first block, so use its address
    1737                */
    1738               dd = rtems_disk_lookup(bd_buf->dev);
    1739               req.req.start = bd_buf->block + dd->start;
    1740             }
    1741             req.req.bufs[req.req.bufnum].length = dd->block_size;
    1742             req.req.bufs[req.req.bufnum].buffer = bd_buf->buffer;
    1743             /*
    1744              * keep bd_buf for postprocessing
    1745              */
    1746             bd_buf_write_store[req.req.bufnum] = bd_buf;
    1747             req.req.count++;
    1748             req.req.bufnum++;
    1749           }
    1750         } while ((bd_buf != NULL) &&
    1751                  (req.req.count < SWAP_OUT_MAX_BLK_CNT));
    1752                  
    1753         /* transfer_sema initialized when bd_buf inserted in the mod chain
    1754            first time */
    1755         result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req);
    1756 
    1757         rtems_disk_release(dd);
    1758        
    1759         for (i = 0;i < req.req.count;i++) {
    1760           bd_buf = bd_buf_write_store[i];
    1761           if (result == -1)
    1762             {
    1763              
    1764               bd_buf->status = RTEMS_IO_ERROR;
    1765               bd_buf->error = errno;
    1766               /* Release tasks waiting on syncing this buffer */
    1767               _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1768                                 CORE_MUTEX_STATUS_SUCCESSFUL);
    1769             }
    1770           else
    1771             {
    1772               if (bd_buf->in_progress)
    1773                 {
    1774                   rtems_interrupt_disable(level);
    1775                   _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level);
    1776                 }
    1777             }
    1778           bd_buf->use_count--;
    1779 
    1780           /* Another task have chance to use this buffer, or even
    1781            * modify it. If buffer is not in use, insert it in appropriate chain
    1782            * and release semaphore */
    1783           if (bd_buf->use_count == 0)
    1784             {
    1785               if (bd_buf->modified)
    1786                 {
    1787                   rtems_chain_append(&rtems_bdbuf_ctx.mod, &bd_buf->link);
    1788                   rc = rtems_semaphore_release(rtems_bdbuf_ctx.flush_sema);
    1789                 }
    1790               else
    1791                 {
    1792                   rtems_chain_append(&bd_pool->lru, &bd_buf->link);
    1793                   rc = rtems_semaphore_release(bd_pool->bufget_sema);
    1794                 }
    1795             }
     2315    boolean update_timers = TRUE;
     2316   
     2317    /*
     2318     * If we write buffers to any disk perform a check again. We only
     2319     * write a single device at a time and a pool may have more than
     2320     * one devices buffers modified waiting to be written.
     2321     */
     2322    boolean transfered_buffers;
     2323
     2324    do
     2325    {
     2326      rtems_bdpool_id pid;
     2327   
     2328      transfered_buffers = FALSE;
     2329
     2330      /*
     2331       * Loop over each pool extacting all the buffers we find for a specific
     2332       * device. The device is the first one we find on a modified list of a
     2333       * pool. Process the sync queue of buffers first.
     2334       */
     2335      for (pid = 0; pid < context->npools; pid++)
     2336      {
     2337        if (rtems_bdbuf_swapout_pool_processing (pid,
     2338                                                 timer_delta,
     2339                                                 update_timers,
     2340                                                 write_req))
     2341        {
     2342          transfered_buffers = TRUE;
    17962343        }
    1797     }
    1798 }
    1799 
    1800 /* rtems_bdbuf_find_pool --
    1801  *     Find first appropriate buffer pool. This primitive returns the index
    1802  *     of first buffer pool which block size is greater than or equal to
    1803  *     specified size.
     2344      }
     2345
     2346      /*
     2347       * Only update the timers once.
     2348       */
     2349      update_timers = FALSE;
     2350    }
     2351    while (transfered_buffers);
     2352
     2353    sc = rtems_event_receive (RTEMS_BDBUF_SWAPOUT_SYNC,
     2354                              RTEMS_EVENT_ALL | RTEMS_WAIT,
     2355                              period_in_ticks,
     2356                              &out);
     2357
     2358    if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT))
     2359      rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
     2360  }
     2361
     2362  free (write_req);
     2363
     2364  rtems_task_delete (RTEMS_SELF);
     2365}
     2366
     2367/**
     2368 * Find first appropriate buffer pool. This primitive returns the index of
     2369 * first buffer pool which block size is greater than or equal to specified
     2370 * size.
    18042371 *
    18052372 * PARAMETERS:
     
    18142381 */
    18152382rtems_status_code
    1816 rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool)
    1817 {
    1818     rtems_bdpool_id i;
    1819     bdbuf_pool *p;
    1820     int cursize = INT_MAX;
    1821     rtems_bdpool_id curid = -1;
    1822     rtems_boolean found = FALSE;
    1823     int j;
    1824 
    1825     for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1);
    1826     if (j != 1)
    1827         return RTEMS_INVALID_SIZE;
    1828 
    1829     for (i = 0, p = rtems_bdbuf_ctx.pool; i < rtems_bdbuf_ctx.npools; i++, p++)
    1830     {
    1831         if ((p->blksize >= block_size) &&
    1832             (p->blksize < cursize))
    1833         {
    1834             curid = i;
    1835             cursize = p->blksize;
    1836             found = TRUE;
    1837         }
    1838     }
    1839 
    1840     if (found)
    1841     {
    1842         if (pool != NULL)
    1843             *pool = curid;
    1844         return RTEMS_SUCCESSFUL;
    1845     }
    1846     else
    1847     {
    1848         return RTEMS_NOT_DEFINED;
    1849     }
    1850 }
    1851 
    1852 /* rtems_bdbuf_get_pool_info --
    1853  *     Obtain characteristics of buffer pool with specified number.
     2383rtems_bdbuf_find_pool (int block_size, rtems_bdpool_id *pool)
     2384{
     2385  rtems_bdbuf_pool* p;
     2386  rtems_bdpool_id   i;
     2387  rtems_bdpool_id   curid = -1;
     2388  rtems_boolean     found = FALSE;
     2389  int               cursize = INT_MAX;
     2390  int               j;
     2391
     2392  for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1);
     2393  if (j != 1)
     2394    return RTEMS_INVALID_SIZE;
     2395
     2396  for (i = 0; i < rtems_bdbuf_ctx.npools; i++)
     2397  {
     2398    p = rtems_bdbuf_get_pool (i);
     2399    if ((p->blksize >= block_size) &&
     2400        (p->blksize < cursize))
     2401    {
     2402      curid = i;
     2403      cursize = p->blksize;
     2404      found = TRUE;
     2405    }
     2406  }
     2407
     2408  if (found)
     2409  {
     2410    if (pool != NULL)
     2411      *pool = curid;
     2412    return RTEMS_SUCCESSFUL;
     2413  }
     2414  else
     2415  {
     2416    return RTEMS_NOT_DEFINED;
     2417  }
     2418}
     2419
     2420/**
     2421 * Obtain characteristics of buffer pool with specified number.
    18542422 *
    18552423 * PARAMETERS:
     
    18672435 */
    18682436rtems_status_code
    1869 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size,
    1870                           int *blocks)
    1871 {
    1872     if (pool >= rtems_bdbuf_ctx.npools)
    1873         return RTEMS_INVALID_NUMBER;
    1874 
    1875     if (block_size != NULL)
    1876     {
    1877         *block_size = rtems_bdbuf_ctx.pool[pool].blksize;
    1878     }
    1879 
    1880     if (blocks != NULL)
    1881     {
    1882         *blocks = rtems_bdbuf_ctx.pool[pool].nblks;
    1883     }
    1884 
    1885     return RTEMS_SUCCESSFUL;
    1886 }
     2437rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int* block_size, int* blocks)
     2438{
     2439  if (pool >= rtems_bdbuf_ctx.npools)
     2440    return RTEMS_INVALID_NUMBER;
     2441
     2442  if (block_size != NULL)
     2443  {
     2444    *block_size = rtems_bdbuf_ctx.pool[pool].blksize;
     2445  }
     2446
     2447  if (blocks != NULL)
     2448  {
     2449    *blocks = rtems_bdbuf_ctx.pool[pool].nblks;
     2450  }
     2451
     2452  return RTEMS_SUCCESSFUL;
     2453}
  • cpukit/libblock/src/blkdev.c

    r1b39f18 r3899a537  
    3939    unsigned int blkofs;
    4040    dev_t dev;
    41     disk_device *dd;
    42 
    43     dev = rtems_filesystem_make_dev_t(major, minor);
    44     dd = rtems_disk_lookup(dev);
     41    rtems_disk_device *dd;
     42
     43    dev = rtems_filesystem_make_dev_t(major, minor);
     44    dd = rtems_disk_obtain(dev);
    4545    if (dd == NULL)
    4646        return RTEMS_INVALID_NUMBER;
     
    5858    while (count > 0)
    5959    {
    60         bdbuf_buffer *diskbuf;
     60        rtems_bdbuf_buffer *diskbuf;
    6161        int copy;
    6262        rtems_status_code rc;
     
    100100    dev_t dev;
    101101    rtems_status_code rc;
    102     disk_device *dd;
    103 
    104     dev = rtems_filesystem_make_dev_t(major, minor);
    105     dd = rtems_disk_lookup(dev);
     102    rtems_disk_device *dd;
     103
     104    dev = rtems_filesystem_make_dev_t(major, minor);
     105    dd = rtems_disk_obtain(dev);
    106106    if (dd == NULL)
    107107        return RTEMS_INVALID_NUMBER;
     
    119119    while (count > 0)
    120120    {
    121         bdbuf_buffer *diskbuf;
     121        rtems_bdbuf_buffer *diskbuf;
    122122        int copy;
    123123
     
    157157{
    158158    dev_t dev;
    159     disk_device *dd;
    160 
    161     dev = rtems_filesystem_make_dev_t(major, minor);
    162     dd = rtems_disk_lookup(dev);
     159    rtems_disk_device *dd;
     160
     161    dev = rtems_filesystem_make_dev_t(major, minor);
     162    dd = rtems_disk_obtain(dev);
    163163    if (dd == NULL)
    164164        return RTEMS_INVALID_NUMBER;
     
    182182{
    183183    dev_t dev;
    184     disk_device *dd;
    185 
    186     dev = rtems_filesystem_make_dev_t(major, minor);
    187     dd = rtems_disk_lookup(dev);
     184    rtems_disk_device *dd;
     185
     186    dev = rtems_filesystem_make_dev_t(major, minor);
     187    dd = rtems_disk_obtain(dev);
    188188    if (dd == NULL)
    189189        return RTEMS_INVALID_NUMBER;
     
    207207    rtems_libio_ioctl_args_t *args = arg;
    208208    dev_t dev;
    209     disk_device *dd;
     209    rtems_disk_device *dd;
    210210    int rc;
    211211
    212212    dev = rtems_filesystem_make_dev_t(major, minor);
    213     dd = rtems_disk_lookup(dev);
     213    dd = rtems_disk_obtain(dev);
    214214    if (dd == NULL)
    215215        return RTEMS_INVALID_NUMBER;
     
    217217    switch (args->command)
    218218    {
    219         case BLKIO_GETBLKSIZE:
     219        case RTEMS_BLKIO_GETBLKSIZE:
    220220            args->ioctl_return = dd->block_size;
    221221            break;
    222222
    223         case BLKIO_GETSIZE:
     223        case RTEMS_BLKIO_GETSIZE:
    224224            args->ioctl_return = dd->size;
    225225            break;
    226226
    227         case BLKIO_SYNCDEV:
     227        case RTEMS_BLKIO_SYNCDEV:
    228228            rc = rtems_bdbuf_syncdev(dd->dev);
    229229            args->ioctl_return = (rc == RTEMS_SUCCESSFUL ? 0 : -1);
    230230            break;
    231231
    232         case BLKIO_REQUEST:
     232        case RTEMS_BLKIO_REQUEST:
    233233        {
    234             blkdev_request *req = args->buffer;
     234            rtems_blkdev_request *req = args->buffer;
    235235            req->start += dd->start;
    236236            args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command,
  • cpukit/libblock/src/diskdevs.c

    r1b39f18 r3899a537  
    2424
    2525/* Table of disk devices having the same major number */
    26 struct disk_device_table {
    27     disk_device **minor; /* minor-indexed disk device table */
     26typedef struct rtems_disk_device_table {
     27    rtems_disk_device **minor; /* minor-indexed disk device table */
    2828    int size;            /* Number of entries in the table */
    29 };
     29} rtems_disk_device_table;
    3030
    3131/* Pointer to [major].minor[minor] indexed array of disk devices */
    32 static struct disk_device_table *disktab;
     32static rtems_disk_device_table *disktab;
    3333
    3434/* Number of allocated entries in disktab table */
     
    6565 *     available for its creation.
    6666 */
    67 static disk_device *
     67static rtems_disk_device *
    6868create_disk_entry(dev_t dev)
    6969{
    7070    rtems_device_major_number major;
    7171    rtems_device_minor_number minor;
    72     struct disk_device **d;
     72    rtems_disk_device **d;
    7373
    7474    rtems_filesystem_split_dev_t (dev, major, minor);
     
    7676    if (major >= disktab_size)
    7777    {
    78         struct disk_device_table *p;
     78        rtems_disk_device_table *p;
    7979        int newsize;
    8080        int i;
     
    8282        if (major >= newsize)
    8383            newsize = major + 1;
    84         p = realloc(disktab, sizeof(struct disk_device_table) * newsize);
     84        p = realloc(disktab, sizeof(rtems_disk_device_table) * newsize);
    8585        if (p == NULL)
    8686            return NULL;
     
    9898    {
    9999        int newsize;
    100         disk_device **p;
     100        rtems_disk_device **p;
    101101        int i;
    102102        int s = disktab[major].size;
     
    109109            newsize = minor + 1;
    110110
    111         p = realloc(disktab[major].minor, sizeof(disk_device *) * newsize);
     111        p = realloc(disktab[major].minor,
     112                    sizeof(rtems_disk_device *) * newsize);
    112113        if (p == NULL)
    113114            return NULL;
     
    122123    if (*d == NULL)
    123124    {
    124         *d = calloc(1, sizeof(disk_device));
     125        *d = calloc(1, sizeof(rtems_disk_device));
    125126    }
    126127    return *d;
     
    137138 *     device number, or NULL if disk device with such number not exists.
    138139 */
    139 static inline disk_device *
     140static rtems_disk_device *
    140141get_disk_entry(dev_t dev)
    141142{
    142143    rtems_device_major_number major;
    143144    rtems_device_minor_number minor;
    144     struct disk_device_table *dtab;
     145    rtems_disk_device_table *dtab;
    145146
    146147    rtems_filesystem_split_dev_t (dev, major, minor);
     
    172173 */
    173174static rtems_status_code
    174 create_disk(dev_t dev, const char *name, disk_device **diskdev)
    175 {
    176     disk_device *dd;
     175create_disk(dev_t dev, const char *name, rtems_disk_device **diskdev)
     176{
     177    rtems_disk_device *dd;
    177178    char *n;
    178179
     
    235236rtems_status_code
    236237rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
    237                        block_device_ioctl handler,
     238                       rtems_block_device_ioctl handler,
    238239                       const char *name)
    239240{
    240241    int bs_log2;
    241242    int i;
    242     disk_device *dd;
     243    rtems_disk_device *dd;
    243244    rtems_status_code rc;
    244245    rtems_bdpool_id pool;
     
    285286    rc = rtems_io_register_name(name, major, minor);
    286287
     288    if (handler (dd->phys_dev->dev,
     289                 RTEMS_BLKDEV_CAPABILITIES,
     290                 &dd->capabilities) < 0)
     291      dd->capabilities = 0;
     292   
    287293    diskdevs_protected = FALSE;
    288294    rtems_semaphore_release(diskdevs_mutex);
     
    318324rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name)
    319325{
    320     disk_device *dd;
    321     disk_device *pdd;
     326    rtems_disk_device *dd;
     327    rtems_disk_device *pdd;
    322328    rtems_status_code rc;
    323329    rtems_device_major_number major;
     
    394400    for (maj = 0; maj < disktab_size; maj++)
    395401    {
    396         struct disk_device_table *dtab = disktab + maj;
     402        rtems_disk_device_table *dtab = disktab + maj;
    397403        if (dtab != NULL)
    398404        {
    399405            for (min = 0; min < dtab->size; min++)
    400406            {
    401                 disk_device *dd = dtab->minor[min];
     407                rtems_disk_device *dd = dtab->minor[min];
    402408                if ((dd != NULL) && (dd->phys_dev->dev == dev))
    403409                    used += dd->uses;
     
    416422    for (maj = 0; maj < disktab_size; maj++)
    417423    {
    418         struct disk_device_table *dtab = disktab +maj;
     424        rtems_disk_device_table *dtab = disktab +maj;
    419425        if (dtab != NULL)
    420426        {
    421427            for (min = 0; min < dtab->size; min++)
    422428            {
    423                 disk_device *dd = dtab->minor[min];
     429                rtems_disk_device *dd = dtab->minor[min];
    424430                if ((dd != NULL) && (dd->phys_dev->dev == dev))
    425431                {
     
    438444}
    439445
    440 /* rtems_disk_lookup --
     446/* rtems_disk_obtain --
    441447 *     Find block device descriptor by its device identifier.
    442448 *
     
    448454 *     exists.
    449455 */
    450 disk_device *
    451 rtems_disk_lookup(dev_t dev)
     456rtems_disk_device *
     457rtems_disk_obtain(dev_t dev)
    452458{
    453459    rtems_interrupt_level level;
    454     disk_device *dd;
     460    rtems_disk_device *dd;
    455461    rtems_status_code rc;
    456462
     
    481487
    482488/* rtems_disk_release --
    483  *     Release disk_device structure (decrement usage counter to 1).
     489 *     Release rtems_disk_device structure (decrement usage counter to 1).
    484490 *
    485491 * PARAMETERS:
     
    490496 */
    491497rtems_status_code
    492 rtems_disk_release(disk_device *dd)
     498rtems_disk_release(rtems_disk_device *dd)
    493499{
    494500    rtems_interrupt_level level;
     
    511517 *     devices enumerated.
    512518 */
    513 disk_device *
     519rtems_disk_device *
    514520rtems_disk_next(dev_t dev)
    515521{
    516522    rtems_device_major_number major;
    517523    rtems_device_minor_number minor;
    518     struct disk_device_table *dtab;
     524    rtems_disk_device_table *dtab;
    519525
    520526    dev++;
     
    563569
    564570    disktab_size = DISKTAB_INITIAL_SIZE;
    565     disktab = calloc(disktab_size, sizeof(struct disk_device_table));
     571    disktab = calloc(disktab_size, sizeof(rtems_disk_device_table));
    566572    if (disktab == NULL)
    567573        return RTEMS_NO_MEMORY;
     
    579585    }
    580586
    581     rc = rtems_bdbuf_init(rtems_bdbuf_configuration,
    582                           rtems_bdbuf_configuration_size);
     587    rc = rtems_bdbuf_init();
    583588
    584589    if (rc != RTEMS_SUCCESSFUL)
     
    613618    for (maj = 0; maj < disktab_size; maj++)
    614619    {
    615         struct disk_device_table *dtab = disktab + maj;
     620        rtems_disk_device_table *dtab = disktab + maj;
    616621        if (dtab != NULL)
    617622        {
    618623            for (min = 0; min < dtab->size; min++)
    619624            {
    620                 disk_device *dd = dtab->minor[min];
     625                rtems_disk_device *dd = dtab->minor[min];
    621626                unlink(dd->name);
    622627                free(dd->name);
  • cpukit/libblock/src/flashdisk.c

    r1b39f18 r3899a537  
    20582058 */
    20592059static int
    2060 rtems_fdisk_read (rtems_flashdisk* fd, blkdev_request* req)
    2061 {
    2062   blkdev_sg_buffer* sg = req->bufs;
    2063   uint32_t          block = req->start;
    2064   uint32_t          b;
    2065   int               ret = 0;
    2066 
    2067   for (b = 0; b < req->bufnum; b++, block++, sg++)
     2060rtems_fdisk_read (rtems_flashdisk* fd, rtems_blkdev_request* req)
     2061{
     2062  rtems_blkdev_sg_buffer* sg = req->bufs;
     2063  uint32_t                b;
     2064  int                     ret = 0;
     2065
     2066  for (b = 0; b < req->bufnum; b++, sg++)
    20682067  {
    20692068    uint32_t length = sg->length;
     
    20782077    }
    20792078
    2080     ret = rtems_fdisk_read_block (fd, block, sg->buffer);
     2079    ret = rtems_fdisk_read_block (fd, sg->block, sg->buffer);
    20812080
    20822081    if (ret)
     
    20992098 */
    21002099static int
    2101 rtems_fdisk_write (rtems_flashdisk* fd, blkdev_request* req)
    2102 {
    2103   blkdev_sg_buffer* sg = req->bufs;
    2104   uint32_t          block = req->start;
    2105   uint32_t          b;
    2106   int               ret = 0;
    2107 
    2108   for (b = 0; b < req->bufnum; b++, block++, sg++)
     2100rtems_fdisk_write (rtems_flashdisk* fd, rtems_blkdev_request* req)
     2101{
     2102  rtems_blkdev_sg_buffer* sg = req->bufs;
     2103  uint32_t                b;
     2104  int                     ret = 0;
     2105
     2106  for (b = 0; b < req->bufnum; b++, sg++)
    21092107  {
    21102108    if (sg->length != fd->block_size)
     
    21142112    }
    21152113
    2116     ret = rtems_fdisk_write_block (fd, block, sg->buffer);
     2114    ret = rtems_fdisk_write_block (fd, sg->block, sg->buffer);
    21172115
    21182116    if (ret)
     
    23572355{
    23582356  rtems_device_minor_number minor = rtems_filesystem_dev_minor_t (dev);
    2359   blkdev_request*           r = argp;
     2357  rtems_blkdev_request*     r = argp;
    23602358  rtems_status_code         sc;
    23612359
     
    23692367    switch (req)
    23702368    {
    2371       case BLKIO_REQUEST:
     2369      case RTEMS_BLKIO_REQUEST:
    23722370        if ((minor >= rtems_flashdisk_count) ||
    23732371            (rtems_flashdisks[minor].device_count == 0))
     
    23792377          switch (r->req)
    23802378          {
    2381             case BLKDEV_REQ_READ:
     2379            case RTEMS_BLKDEV_REQ_READ:
    23822380              errno = rtems_fdisk_read (&rtems_flashdisks[minor], r);
    23832381              break;
    23842382
    2385             case BLKDEV_REQ_WRITE:
     2383            case RTEMS_BLKDEV_REQ_WRITE:
    23862384              errno = rtems_fdisk_write (&rtems_flashdisks[minor], r);
    23872385              break;
  • cpukit/libblock/src/ide_part_table.c

    r1b39f18 r3899a537  
    4747 */
    4848static rtems_status_code
    49 get_sector(dev_t dev, uint32_t sector_num, sector_data_t **sector)
    50 {
    51     sector_data_t      *s;
    52     bdbuf_buffer       *buf;
    53     rtems_status_code   rc;
     49get_sector(dev_t dev, uint32_t sector_num, rtems_sector_data_t **sector)
     50{
     51    rtems_sector_data_t *s;
     52    rtems_bdbuf_buffer  *buf;
     53    rtems_status_code    rc;
    5454
    5555    if (sector == NULL)
     
    5858    }
    5959
    60     s = (sector_data_t *) malloc(sizeof(sector_data_t) + RTEMS_IDE_SECTOR_SIZE);
     60    s = (rtems_sector_data_t *) malloc(sizeof(rtems_sector_data_t) + RTEMS_IDE_SECTOR_SIZE);
    6161    if (s == NULL)
    6262    {
     
    9393 */
    9494static rtems_boolean
    95 msdos_signature_check (sector_data_t *sector)
     95msdos_signature_check (rtems_sector_data_t *sector)
    9696{
    9797    uint8_t *p = sector->data + RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET;
     
    157157 */
    158158static rtems_status_code
    159 data_to_part_desc(uint8_t *data, part_desc_t **new_part_desc)
    160 {
    161     part_desc_t *part_desc;
    162     uint32_t     temp;
     159data_to_part_desc(uint8_t *data, rtems_part_desc_t **new_part_desc)
     160{
     161    rtems_part_desc_t *part_desc;
     162    uint32_t           temp;
    163163
    164164    if (new_part_desc == NULL)
     
    169169    *new_part_desc = NULL;
    170170
    171     if ((part_desc = calloc(1, sizeof(part_desc_t))) == NULL)
     171    if ((part_desc = calloc(1, sizeof(rtems_part_desc_t))) == NULL)
    172172    {
    173173        return RTEMS_NO_MEMORY;
     
    220220 */
    221221static rtems_status_code
    222 read_extended_partition(uint32_t start, part_desc_t *ext_part)
    223 {
    224     int                 i;
    225     dev_t               dev;
    226     sector_data_t      *sector;
    227     uint32_t            here;
    228     uint8_t            *data;
    229     part_desc_t        *new_part_desc;
    230     rtems_status_code   rc;
     222read_extended_partition(uint32_t start, rtems_part_desc_t *ext_part)
     223{
     224    int                  i;
     225    dev_t                dev;
     226    rtems_sector_data_t *sector;
     227    uint32_t             here;
     228    uint8_t             *data;
     229    rtems_part_desc_t   *new_part_desc;
     230    rtems_status_code    rc;
    231231
    232232    if ((ext_part == NULL) || (ext_part->disk_desc == NULL))
     
    287287        else
    288288        {
    289             disk_desc_t *disk_desc = new_part_desc->disk_desc;
     289            rtems_disk_desc_t *disk_desc = new_part_desc->disk_desc;
    290290            disk_desc->partitions[disk_desc->last_log_id] = new_part_desc;
    291291            new_part_desc->log_id = ++disk_desc->last_log_id;
     
    315315 */
    316316static rtems_status_code
    317 read_mbr(disk_desc_t *disk_desc)
    318 {
    319     int                 part_num;
    320     sector_data_t      *sector;
    321     part_desc_t        *part_desc;
    322     uint8_t            *data;
    323     rtems_status_code   rc;
    324     dev_t               dev = disk_desc->dev;
     317read_mbr(rtems_disk_desc_t *disk_desc)
     318{
     319    int                  part_num;
     320    rtems_sector_data_t *sector;
     321    rtems_part_desc_t   *part_desc;
     322    uint8_t             *data;
     323    rtems_status_code    rc;
     324    dev_t                dev = disk_desc->dev;
    325325
    326326    /* get MBR sector */
     
    399399 */
    400400static void
    401 partition_free(part_desc_t *part_desc)
     401partition_free(rtems_part_desc_t *part_desc)
    402402{
    403403    int part_num;
     
    430430 */
    431431void
    432 rtems_ide_part_table_free(disk_desc_t *disk_desc)
     432rtems_ide_part_table_free(rtems_disk_desc_t *disk_desc)
    433433{
    434434    int part_num;
     
    456456 */
    457457rtems_status_code
    458 rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc)
     458rtems_ide_part_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc)
    459459{
    460460    struct stat         dev_stat;
     
    495495    int                         part_num;
    496496    dev_t                       dev;
    497     disk_desc_t                *disk_desc;
     497    rtems_disk_desc_t          *disk_desc;
    498498    rtems_device_major_number   major;
    499499    rtems_device_minor_number   minor;
    500500    rtems_status_code           rc;
    501     part_desc_t                *part_desc;
     501    rtems_part_desc_t          *part_desc;
    502502
    503503    /* logical device name /dev/hdxyy */
    504504    char                        name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX];
    505505
    506     disk_desc = (disk_desc_t *) calloc(1, sizeof(disk_desc_t));
     506    disk_desc = (rtems_disk_desc_t *) calloc(1, sizeof(rtems_disk_desc_t));
    507507    if (disk_desc == NULL)
    508508    {
  • cpukit/libblock/src/nvdisk.c

    r1b39f18 r3899a537  
    5252 */
    5353#if !defined (RTEMS_NVDISK_TRACE)
    54 #define RTEMS_NVDISK_TRACE 1
     54#define RTEMS_NVDISK_TRACE 0
    5555#endif
    5656
     
    166166 * Print a message to the nvdisk output and flush it.
    167167 *
    168  * @param fd The flashdisk control structure.
     168 * @param nvd The nvdisk control structure.
    169169 * @param format The format string. See printf for details.
    170170 * @param ... The arguments for the format text.
     
    190190 * Print a info message to the nvdisk output and flush it.
    191191 *
    192  * @param fd The flashdisk control structure.
     192 * @param nvd The nvdisk control structure.
    193193 * @param format The format string. See printf for details.
    194194 * @param ... The arguments for the format text.
     
    214214 * Print a warning to the nvdisk output and flush it.
    215215 *
    216  * @param fd The flashdisk control structure.
     216 * @param nvd The nvdisk control structure.
    217217 * @param format The format string. See printf for details.
    218218 * @param ... The arguments for the format text.
     
    257257
    258258/**
    259  * Print an abort message, flush it then abort the program.
    260  *
    261  * @param format The format string. See printf for details.
    262  * @param ... The arguments for the format text.
    263  */
    264 static void
    265 rtems_nvdisk_abort (const char *format, ...)
    266 {
    267   va_list args;
    268   va_start (args, format);
    269   fprintf (stderr, "nvdisk:abort:");
    270   vfprintf (stderr, format, args);
    271   fprintf (stderr, "\n");
    272   fflush (stderr);
    273   exit (1);
    274 }
    275 
    276 /**
    277259 * Get the descriptor for a device.
    278260 */
     
    325307}
    326308
     309#if NOT_USED
    327310/**
    328311 * Verify the data with the data in a segment.
     
    345328  return ops->verify (device, dd->flags, dd->base, offset, buffer, size);
    346329}
     330#endif
    347331
    348332/**
     
    372356                                    page * nvd->block_size,
    373357                                    buffer, nvd->block_size);
    374 }
    375 
    376 /**
    377  * Verify a page of data with the data in the device.
    378  */
    379 static int
    380 rtems_nvdisk_verify_page (const rtems_nvdisk* nvd,
    381                           uint32_t            device,
    382                           uint32_t            page,
    383                           const void*         buffer)
    384 {
    385   return rtems_nvdisk_device_verify (nvd, device,
    386                                      page * nvd->block_size,
    387                                      buffer, nvd->block_size);
    388358}
    389359
     
    533503  if (crc == 0xffff)
    534504  {
     505#if RTEMS_NVDISK_TRACE
    535506    rtems_nvdisk_warning (nvd, "read-block: crc not set: %d", block);
     507#endif
    536508    memset (buffer, 0, nvd->block_size);
    537509    return 0;
     
    606578 */
    607579static int
    608 rtems_nvdisk_read (rtems_nvdisk* nvd, blkdev_request* req)
    609 {
    610   blkdev_sg_buffer* sg = req->bufs;
    611   uint32_t          block = req->start;
    612   uint32_t          b;
    613   int32_t           remains;
    614   int               ret = 0;
     580rtems_nvdisk_read (rtems_nvdisk* nvd, rtems_blkdev_request* req)
     581{
     582  rtems_blkdev_sg_buffer* sg = req->bufs;
     583  uint32_t                b;
     584  int32_t                 remains;
     585  int                     ret = 0;
    615586
    616587#if RTEMS_NVDISK_TRACE
     
    620591  remains = req->count * nvd->block_size;
    621592 
    622   for (b = 0; b < req->bufnum; b++, block++, sg++)
     593  for (b = 0; b < req->bufnum; b++, sg++)
    623594  {
    624595    uint32_t length = sg->length;
     
    659630 */
    660631static int
    661 rtems_nvdisk_write (rtems_nvdisk* nvd, blkdev_request* req)
    662 {
    663   blkdev_sg_buffer* sg = req->bufs;
    664   uint32_t          block = req->start;
    665   uint32_t          b;
    666   int               ret = 0;
     632rtems_nvdisk_write (rtems_nvdisk* nvd, rtems_blkdev_request* req)
     633{
     634  rtems_blkdev_sg_buffer* sg = req->bufs;
     635  uint32_t                b;
     636  int                     ret = 0;
    667637
    668638#if RTEMS_NVDISK_TRACE
     
    670640#endif
    671641
    672   for (b = 0; b < req->bufnum; b++, block++, sg++)
     642  for (b = 0; b < req->bufnum; b++, sg++)
    673643  {
    674644    if (sg->length != nvd->block_size)
     
    721691
    722692/**
    723  * MV disk IOCTL handler.
     693 * NV disk IOCTL handler.
    724694 *
    725695 * @param dev Device number (major, minor number).
     
    732702{
    733703  rtems_device_minor_number minor = rtems_filesystem_dev_minor_t (dev);
    734   blkdev_request*           r = argp;
     704  rtems_blkdev_request*     r = argp;
    735705  rtems_status_code         sc;
    736706
     707  if (minor >= rtems_nvdisk_count)
     708  {
     709    errno = ENODEV;
     710    return -1;
     711  }
     712       
     713  if (rtems_nvdisks[minor].device_count == 0)
     714  {
     715    errno = ENODEV;
     716    return -1;
     717  }
     718       
    737719  errno = 0;
    738720
     
    744726    switch (req)
    745727    {
    746       case BLKIO_REQUEST:
    747         if ((minor >= rtems_nvdisk_count) ||
    748             (rtems_nvdisks[minor].device_count == 0))
     728      case RTEMS_BLKIO_REQUEST:
     729        switch (r->req)
    749730        {
    750           errno = ENODEV;
    751         }
    752         else
    753         {
    754           switch (r->req)
    755           {
    756             case BLKDEV_REQ_READ:
    757               errno = rtems_nvdisk_read (&rtems_nvdisks[minor], r);
    758               break;
    759 
    760             case BLKDEV_REQ_WRITE:
    761               errno = rtems_nvdisk_write (&rtems_nvdisks[minor], r);
    762               break;
    763        
    764             default:
    765               errno = EBADRQC;
    766               break;
    767           }
     731          case RTEMS_BLKDEV_REQ_READ:
     732            errno = rtems_nvdisk_read (&rtems_nvdisks[minor], r);
     733            break;
     734           
     735          case RTEMS_BLKDEV_REQ_WRITE:
     736            errno = rtems_nvdisk_write (&rtems_nvdisks[minor], r);
     737            break;
     738           
     739          default:
     740            errno = EBADRQC;
     741            break;
    768742        }
    769743        break;
     
    772746        errno = rtems_nvdisk_erase_disk (&rtems_nvdisks[minor]);
    773747        break;
    774 
     748       
    775749      case RTEMS_NVDISK_IOCTL_INFO_LEVEL:
    776750        rtems_nvdisks[minor].info_level = (uint32_t) argp;
    777751        break;
    778 
     752       
    779753      default:
    780754        errno = EBADRQC;
  • cpukit/libblock/src/ramdisk.c

    r1b39f18 r3899a537  
    2222#include "rtems/diskdevs.h"
    2323#include "rtems/ramdisk.h"
     24
     25/**
     26 * Control tracing. It can be compiled out of the code for small
     27 * footprint targets. Leave in by default.
     28 */
     29#if !defined (RTEMS_RAMDISK_TRACE)
     30#define RTEMS_RAMDISK_TRACE 0
     31#endif
    2432
    2533#define RAMDISK_DEVICE_BASE_NAME "/dev/ramdisk"
     
    3341    rtems_boolean malloced;   /* != 0, if memory allocated by malloc for this
    3442                                 RAM disk */
     43#if RTEMS_RAMDISK_TRACE
     44    int           info_level; /* Trace level */
     45#endif
    3546};
    3647
    3748static struct ramdisk *ramdisk;
    3849static int nramdisks;
     50
     51#if RTEMS_RAMDISK_TRACE
     52/**
     53 * Print a message to the ramdisk output and flush it.
     54 *
     55 * @param rd The ramdisk control structure.
     56 * @param format The format string. See printf for details.
     57 * @param ... The arguments for the format text.
     58 * @return int The number of bytes written to the output.
     59 */
     60static int
     61rtems_ramdisk_printf (struct ramdisk *rd, const char *format, ...)
     62{
     63  int ret = 0;
     64  if (rd->info_level >= 1)
     65  {
     66    va_list args;
     67    va_start (args, format);
     68    fprintf (stdout, "ramdisk:");
     69    ret =  vfprintf (stdout, format, args);
     70    fprintf (stdout, "\n");
     71    fflush (stdout);
     72  }
     73  return ret;
     74}
     75#endif
    3976
    4077/* ramdisk_read --
     
    5087 */
    5188static int
    52 ramdisk_read(struct ramdisk *rd, blkdev_request *req)
     89ramdisk_read(struct ramdisk *rd, rtems_blkdev_request *req)
    5390{
    5491    char *from;
    5592    uint32_t   i;
    56     blkdev_sg_buffer *sg;
     93    rtems_blkdev_sg_buffer *sg;
    5794    uint32_t   remains;
    5895
    59     from = (char *)rd->area + (req->start * rd->block_size);
     96#if RTEMS_RAMDISK_TRACE
     97    rtems_ramdisk_printf (rd, "ramdisk read: start=%d, blocks=%d remains=%d",
     98                          req->bufs[0].block, req->bufnum,
     99                          rd->block_size * req->count);
     100#endif
     101
    60102    remains = rd->block_size * req->count;
    61103    sg = req->bufs;
     
    63105    {
    64106        int count = sg->length;
     107        from = ((char *)rd->area + (sg->block * rd->block_size));
    65108        if (count > remains)
    66109            count = remains;
     
    85128 */
    86129static int
    87 ramdisk_write(struct ramdisk *rd, blkdev_request *req)
     130ramdisk_write(struct ramdisk *rd, rtems_blkdev_request *req)
    88131{
    89132    char *to;
    90133    uint32_t   i;
    91     blkdev_sg_buffer *sg;
     134    rtems_blkdev_sg_buffer *sg;
    92135    uint32_t   remains;
    93136
    94     to = (char *)rd->area + (req->start * rd->block_size);
     137#if RTEMS_RAMDISK_TRACE
     138    rtems_ramdisk_printf (rd, "ramdisk write: start=%d, blocks=%d remains=%d",
     139                          req->bufs[0].block, req->bufnum,
     140                          rd->block_size * req->count);
     141#endif
    95142    remains = rd->block_size * req->count;
    96143    sg = req->bufs;
     
    98145    {
    99146        int count = sg->length;
     147        to = ((char *)rd->area + (sg->block * rd->block_size));
    100148        if (count > remains)
    101149            count = remains;
     
    124172    switch (req)
    125173    {
    126         case BLKIO_REQUEST:
     174        case RTEMS_BLKIO_REQUEST:
    127175        {
    128176            rtems_device_minor_number minor;
    129             blkdev_request *r = argp;
     177            rtems_blkdev_request *r = argp;
    130178            struct ramdisk *rd;
    131179
     
    141189            switch (r->req)
    142190            {
    143                 case BLKDEV_REQ_READ:
     191                case RTEMS_BLKDEV_REQ_READ:
    144192                    return ramdisk_read(rd, r);
    145193
    146                 case BLKDEV_REQ_WRITE:
     194                case RTEMS_BLKDEV_REQ_WRITE:
    147195                    return ramdisk_write(rd, r);
    148196
     
    189237    r = ramdisk = calloc(rtems_ramdisk_configuration_size,
    190238                         sizeof(struct ramdisk));
    191 
     239#if RTEMS_RAMDISK_TRACE
     240    r->info_level = 1;
     241#endif   
    192242    for (i = 0; i < rtems_ramdisk_configuration_size; i++, c++, r++)
    193243    {
Note: See TracChangeset for help on using the changeset viewer.