From 5c587596f09da0c52528bcb6a0c3726fcd2cfb07 Mon Sep 17 00:00:00 2001 From: Thomas Doerfler Date: Tue, 19 Jan 2010 09:10:03 +0000 Subject: libblock API update --- c/src/libchip/i2c/spi-sd-card.c | 8 +- c/src/libchip/ide/ata.c | 40 +-- c/src/libchip/ide/ata_internal.h | 6 +- c/src/wrapup/Makefile.am | 1 + cpukit/ChangeLog | 18 ++ cpukit/libblock/include/rtems/bdbuf.h | 123 ++++--- cpukit/libblock/include/rtems/blkdev.h | 23 +- cpukit/libblock/src/bdbuf.c | 568 ++++++++++++++++----------------- cpukit/libblock/src/flashdisk.c | 6 +- cpukit/libblock/src/nvdisk.c | 6 +- cpukit/libblock/src/ramdisk-driver.c | 4 +- 11 files changed, 402 insertions(+), 401 deletions(-) diff --git a/c/src/libchip/i2c/spi-sd-card.c b/c/src/libchip/i2c/spi-sd-card.c index 291d96b4a8..11380952d7 100644 --- a/c/src/libchip/i2c/spi-sd-card.c +++ b/c/src/libchip/i2c/spi-sd-card.c @@ -1005,7 +1005,7 @@ static int sd_card_disk_block_read( sd_card_driver_entry *e, rtems_blkdev_reques RTEMS_CHECK_SC_RV( sc, "Stop"); /* Done */ - r->req_done( r->done_arg, RTEMS_SUCCESSFUL, 0); + r->req_done( r->done_arg, RTEMS_SUCCESSFUL); return 0; @@ -1020,7 +1020,7 @@ sd_card_disk_block_read_cleanup: sd_card_stop( e); /* Done */ - r->req_done( r->done_arg, RTEMS_IO_ERROR, 0); + r->req_done( r->done_arg, RTEMS_IO_ERROR); return rv; } @@ -1094,7 +1094,7 @@ static int sd_card_disk_block_write( sd_card_driver_entry *e, rtems_blkdev_reque RTEMS_CHECK_SC_RV( sc, "Stop"); /* Done */ - r->req_done( r->done_arg, RTEMS_SUCCESSFUL, 0); + r->req_done( r->done_arg, RTEMS_SUCCESSFUL); return 0; @@ -1113,7 +1113,7 @@ sd_card_disk_block_write_cleanup: sd_card_stop( e); /* Done */ - r->req_done( r->done_arg, RTEMS_IO_ERROR, 0); + r->req_done( r->done_arg, RTEMS_IO_ERROR); return rv; } diff --git a/c/src/libchip/ide/ata.c b/c/src/libchip/ide/ata.c index 6a12c4efa0..e1fdd58b9d 100644 --- a/c/src/libchip/ide/ata.c +++ b/c/src/libchip/ide/ata.c @@ -546,7 +546,7 @@ ata_process_request(rtems_device_minor_number ctrl_minor) */ static inline void ata_request_done(ata_req_t *areq, rtems_device_minor_number ctrl_minor, - rtems_status_code status, int error) + rtems_status_code status) { assert(areq); @@ -554,7 +554,7 @@ ata_request_done(ata_req_t *areq, rtems_device_minor_number ctrl_minor, ata_printf("ata_request_done: entry\n"); #endif - ATA_EXEC_CALLBACK(areq, status, error); + ATA_EXEC_CALLBACK(areq, status); rtems_chain_extract(&areq->link); if (!rtems_chain_is_empty(&ata_ide_ctrls[ctrl_minor].reqs)) @@ -586,14 +586,14 @@ ata_request_done(ata_req_t *areq, rtems_device_minor_number ctrl_minor, static inline void ata_non_data_request_done(ata_req_t *areq, rtems_device_minor_number ctrl_minor, - rtems_status_code status, int error) + rtems_status_code status, int info) { #if ATA_DEBUG ata_printf("ata_non_data_request_done: entry\n"); #endif areq->status = status; - areq->error = error; + areq->info = info; rtems_semaphore_release(areq->sema); } @@ -784,7 +784,7 @@ ata_pio_in_protocol(rtems_device_minor_number ctrl_minor, ata_req_t *areq) if (areq->cnt == 0) { - ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL, RTEMS_SUCCESSFUL); + ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL); } else if (IDE_Controller_Table[ctrl_minor].int_driven == false) { @@ -822,7 +822,7 @@ ata_pio_out_protocol(rtems_device_minor_number ctrl_minor, ata_req_t *areq) if (areq->cnt == 0) { - ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL, RTEMS_SUCCESSFUL); + ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL); } else { @@ -909,8 +909,7 @@ ata_queue_task(rtems_task_argument arg) * status and start processing of the next request in the * controller queue */ - ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL, - msg.error); + ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL); break; case ATA_MSG_ERROR_EVT: @@ -919,8 +918,7 @@ ata_queue_task(rtems_task_argument arg) * status and start processing of the next request in the * controller queue */ - ata_request_done(areq, ctrl_minor, RTEMS_UNSATISFIED, - msg.error); + ata_request_done(areq, ctrl_minor, RTEMS_IO_ERROR); break; case ATA_MSG_GEN_EVT: @@ -948,8 +946,7 @@ ata_queue_task(rtems_task_argument arg) RTEMS_UNSATISFIED, RTEMS_IO_ERROR); else - ata_request_done(areq, ctrl_minor, RTEMS_UNSATISFIED, - RTEMS_IO_ERROR); + ata_request_done(areq, ctrl_minor, RTEMS_IO_ERROR); break; } } @@ -977,9 +974,7 @@ ata_queue_task(rtems_task_argument arg) #if ATA_DEBUG ata_printf("ata_queue_task: non-supported command type\n"); #endif - ata_request_done(areq, ctrl_minor, - RTEMS_UNSATISFIED, - RTEMS_NOT_IMPLEMENTED); + ata_request_done(areq, ctrl_minor, RTEMS_IO_ERROR); break; } break; @@ -1315,19 +1310,19 @@ rtems_ata_initialize(rtems_device_major_number major, if (breq.req.status == RTEMS_SUCCESSFUL) { /* disassemble returned diagnostic codes */ - if (breq.req.error == ATA_DEV0_PASSED_DEV1_PASSED_OR_NOT_PRSNT) + if (areq.info == ATA_DEV0_PASSED_DEV1_PASSED_OR_NOT_PRSNT) { printk("ATA: ctrl:%d: primary, secondary\n", ctrl_minor); ATA_DEV_INFO(ctrl_minor,0).present = true; ATA_DEV_INFO(ctrl_minor,1).present = true; } - else if (breq.req.error == ATA_DEV0_PASSED_DEV1_FAILED) + else if (areq.info == ATA_DEV0_PASSED_DEV1_FAILED) { printk("ATA: ctrl:%d: primary\n", ctrl_minor); ATA_DEV_INFO(ctrl_minor,0).present = true; ATA_DEV_INFO(ctrl_minor,1).present = false; } - else if (breq.req.error < ATA_DEV1_PASSED_DEV0_FAILED) + else if (areq.info < ATA_DEV1_PASSED_DEV0_FAILED) { printk("ATA: ctrl:%d: secondary\n", ctrl_minor); ATA_DEV_INFO(ctrl_minor,0).present = false; @@ -1521,7 +1516,6 @@ ata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor, if ( 10000 == retries ) { /* probably no drive connected */ areq->breq->status = RTEMS_UNSATISFIED; - areq->breq->error = RTEMS_IO_ERROR; return; } } @@ -1545,8 +1539,7 @@ ata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor, if (val & IDE_REGISTER_STATUS_ERR) { - areq->breq->status = RTEMS_UNSATISFIED; - areq->breq->error = RTEMS_IO_ERROR; + areq->breq->status = RTEMS_IO_ERROR; return; } @@ -1579,15 +1572,14 @@ ata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor, case ATA_COMMAND_TYPE_NON_DATA: areq->breq->status = RTEMS_SUCCESSFUL; - areq->breq->error = val1; + areq->info = val1; break; default: #if ATA_DEBUG ata_printf("ata_queue_task: non-supported command type\n"); #endif - areq->breq->status = RTEMS_UNSATISFIED; - areq->breq->error = RTEMS_NOT_IMPLEMENTED; + areq->breq->status = RTEMS_IO_ERROR; break; } } diff --git a/c/src/libchip/ide/ata_internal.h b/c/src/libchip/ide/ata_internal.h index 99f98618b7..d0f5ccdeea 100644 --- a/c/src/libchip/ide/ata_internal.h +++ b/c/src/libchip/ide/ata_internal.h @@ -210,14 +210,14 @@ typedef struct ata_req_s { * processing of the ata request is required */ rtems_status_code status; /* status of ata request processing */ - int error; /* device error code */ + int info; /* device info code */ } ata_req_t; /* call callback provided by block device request if it is defined */ -#define ATA_EXEC_CALLBACK(areq, status, error) \ +#define ATA_EXEC_CALLBACK(areq, status) \ do {\ if (((areq)->breq != NULL) && ((areq)->breq->req_done != NULL)) \ - (areq)->breq->req_done((areq)->breq->done_arg, status, error); \ + (areq)->breq->req_done((areq)->breq->done_arg, status); \ } while (0) /* ATA RTEMS driver events types */ diff --git a/c/src/wrapup/Makefile.am b/c/src/wrapup/Makefile.am index 33b3ca699c..1841ac3f8f 100644 --- a/c/src/wrapup/Makefile.am +++ b/c/src/wrapup/Makefile.am @@ -25,6 +25,7 @@ if HAS_NETWORKING SRCS += ../libchip/libnetchip.a endif SRCS += ../libchip/libi2cio.a +SRCS += ../libchip/libdisplay.a if HAS_MP SRCS += ../libchip/shmdr.rel diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index ab4131826f..11da38494e 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,21 @@ +2010-01-18 Sebastian Huber + + * libblock/include/rtems/bdbuf.h: Documentation. Renamed + RTEMS_BDBUF_STATE_EMPTY in RTEMS_BDBUF_STATE_FREE. Renamed + RTEMS_BDBUF_STATE_FRESH in RTEMS_BDBUF_STATE_EMPTY. Renamed + RTEMS_BDBUF_STATE_ACCESS in RTEMS_BDBUF_STATE_ACCESS_CACHED. New + state RTEMS_BDBUF_STATE_ACCESS_EMPTY. Removed error field from + rtems_bdbuf_buffer. + * libblock/include/rtems/blkdev.h: Documentation. Removed error + field from block device IO control. + * libblock/src/bdbuf.c: Update for block device API change. New block + device driver error policies. A transfer error or a write to a + deleted disk will invalidate the block data now. See test + "libtests/block09". A get and release sequence will no longer trigger + a disk write. + * libblock/src/flashdisk.c, libblock/src/nvdisk.c, + libblock/src/ramdisk-driver.c: Update for block device API change. + 2010-01-18 Joel Sherrill Coverity Id 27 diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h index 49e3cc59c1..f4e87568da 100644 --- a/cpukit/libblock/include/rtems/bdbuf.h +++ b/cpukit/libblock/include/rtems/bdbuf.h @@ -80,11 +80,12 @@ extern "C" { * @dot * digraph state { * size="16,8"; - * e [label="EMPTY",style="filled",fillcolor="aquamarine"]; - * f [label="FRESH",style="filled",fillcolor="seagreen"]; + * f [label="FREE",style="filled",fillcolor="aquamarine"]; + * e [label="EMPTY",style="filled",fillcolor="seagreen"]; * c [label="CACHED",style="filled",fillcolor="chartreuse"]; - * a [label="ACCESS",style="filled",fillcolor="royalblue"]; + * ac [label="ACCESS CACHED",style="filled",fillcolor="royalblue"]; * am [label="ACCESS MODIFIED",style="filled",fillcolor="royalblue"]; + * ae [label="ACCESS EMPTY",style="filled",fillcolor="royalblue"]; * t [label="TRANSFER",style="filled",fillcolor="red"]; * s [label="SYNC",style="filled",fillcolor="red"]; * m [label="MODIFIED",style="filled",fillcolor="gold"]; @@ -93,22 +94,28 @@ extern "C" { * legend_transfer [label="Transfer Wake-Up",fontcolor="red",shape="none"]; * legend_access [label="Access Wake-Up",fontcolor="royalblue",shape="none"]; * - * i -> e [label="Init"]; - * e -> f [label="Buffer Recycle"]; - * f -> a [label="Get"]; - * f -> t [label="Read\nRead Ahead"]; - * c -> e [label="Reallocate\nBlock Size Changed"]; - * c -> a [label="Get\nRead"]; - * c -> f [label="Buffer Recycle"]; - * t -> c [label="Write Transfer Done\nRead Transfer Done\nRead Ahead Transfer Done",color="red",fontcolor="red"]; + * i -> f [label="Init"]; + * f -> e [label="Buffer Recycle"]; + * e -> ae [label="Get"]; + * e -> t [label="Read\nRead Ahead"]; + * c -> f [label="Reallocate\nBlock Size Changed"]; + * c -> ac [label="Get\nRead"]; + * c -> e [label="Buffer Recycle"]; + * t -> c [label="Transfer Done",color="red",fontcolor="red"]; + * t -> e [label="Transfer Error With Waiter",color="red",fontcolor="red"]; + * t -> f [label="Transfer Error Without Waiter",color="red",fontcolor="red"]; * m -> t [label="Swapout"]; * m -> s [label="Block Size Changed"]; * m -> am [label="Get\nRead"]; - * a -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"]; - * a -> s [label="Sync",color="royalblue",fontcolor="royalblue"]; - * a -> c [label="Release",color="royalblue",fontcolor="royalblue"]; + * ac -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"]; + * ac -> s [label="Sync",color="royalblue",fontcolor="royalblue"]; + * ac -> c [label="Release",color="royalblue",fontcolor="royalblue"]; * am -> m [label="Release\nRelease Modified",color="royalblue",fontcolor="royalblue"]; * am -> s [label="Sync",color="royalblue",fontcolor="royalblue"]; + * ae -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"]; + * ae -> s [label="Sync",color="royalblue",fontcolor="royalblue"]; + * ae -> e [label="Release With Waiter",color="royalblue",fontcolor="royalblue"]; + * ae -> f [label="Release Without Waiter",color="royalblue",fontcolor="royalblue"]; * s -> t [label="Swapout"]; * } * @enddot @@ -164,69 +171,95 @@ extern "C" { * * The state has several implications. Depending on the state a buffer can be * in the AVL tree, in a list, in use by an entity and a group user or not. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
StateValid DataAVL TreeLRU ListModified ListSynchronization ListGroup UserExternal User
FREEX
EMPTYXX
CACHEDXXX
ACCESS_CACHEDXXXX
ACCESS_MODIFIEDXXXX
ACCESS_EMPTYXXX
MODIFIEDXXXX
SYNCXXXX
TRANSFERXXXX
*/ typedef enum { /** - * @brief Empty. - * - * Not in the AVL tree. Not in a list. Not in use. Not a user of its - * group. + * @brief Free. */ - RTEMS_BDBUF_STATE_EMPTY = 0, + RTEMS_BDBUF_STATE_FREE = 0, /** - * @brief Fresh. - * - * In the AVL tree. Not in a list. In use by a get or read request. A user - * of its group. + * @brief Empty. */ - RTEMS_BDBUF_STATE_FRESH, + RTEMS_BDBUF_STATE_EMPTY, /** * @brief Cached. - * - * In the AVL tree. In the LRU list. Not in use. Not a user of its group. */ RTEMS_BDBUF_STATE_CACHED, /** - * @brief Accessed by upper layer. - * - * In the AVL tree. Not in a list. In use by an upper layer. A user of its - * group. + * @brief Accessed by upper layer with cached data. */ - RTEMS_BDBUF_STATE_ACCESS, + RTEMS_BDBUF_STATE_ACCESS_CACHED, /** - * @brief Accessed and modified by upper layer. - * - * In the AVL tree. Not in a list. In use by an upper layer. A user of its - * group. + * @brief Accessed by upper layer with modified data. */ RTEMS_BDBUF_STATE_ACCESS_MODIFIED, + /** + * @brief Accessed by upper layer with invalid data. + */ + RTEMS_BDBUF_STATE_ACCESS_EMPTY, + /** * @brief Modified by upper layer. - * - * In the AVL tree. In the modified list. In use by swapout mechanic. A - * user of its group. */ RTEMS_BDBUF_STATE_MODIFIED, /** * @brief Scheduled for synchronization. - * - * In the AVL tree. In the sync list. In use by swapout mechanic. A user - * of its group. */ RTEMS_BDBUF_STATE_SYNC, /** * @brief In transfer by block device driver. - * - * In the AVL tree. Not in a list. In use by the block device driver. A - * user of its group. */ RTEMS_BDBUF_STATE_TRANSFER } rtems_bdbuf_buf_state; @@ -260,8 +293,6 @@ typedef struct rtems_bdbuf_buffer rtems_blkdev_bnum block; /**< block number on the device */ unsigned char* buffer; /**< Pointer to the buffer memory area */ - int error; /**< If not 0 indicate an error value (errno) - * which can be used by user later */ volatile rtems_bdbuf_buf_state state; /**< State of the buffer. */ diff --git a/cpukit/libblock/include/rtems/blkdev.h b/cpukit/libblock/include/rtems/blkdev.h index eb53700f40..63fb2db108 100644 --- a/cpukit/libblock/include/rtems/blkdev.h +++ b/cpukit/libblock/include/rtems/blkdev.h @@ -59,16 +59,17 @@ typedef enum rtems_blkdev_request_op { #define RTEMS_BLKDEV_CAP_MULTISECTOR_CONT (1 << 0) /** - * Type for block device request done callback function. + * @brief Block device request done callback function type. * - * @param arg Argument supplied in @ref rtems_blkdev_request. - * @param status Status code for this operation. - * @param errno The @c errno value to be passed to the user when status is not - * equal to @c RTEMS_SUCCESSFUL. + * The first parameter @a arg must be the argument provided by the block device + * request structure @ref rtems_blkdev_request. + * + * The second parameter @a status should contain the status of the operation: + * - @c RTEMS_SUCCESSFUL Operation was successful. + * - @c RTEMS_IO_ERROR Some sort of input or output error. + * - @c RTEMS_UNSATISFIED Media no more present. */ -typedef void (* rtems_blkdev_request_cb)(void *arg, - rtems_status_code status, - int error); +typedef void (*rtems_blkdev_request_cb)(void *arg, rtems_status_code status); /** * Block device scatter or gather buffer structure. @@ -127,12 +128,6 @@ typedef struct rtems_blkdev_request { */ rtems_status_code status; - /** - * If @c status is not equal to @c RTEMS_SUCCESSFUL, this field contains the - * error number. - */ - int error; - /** * Number of blocks for this request. */ diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c index 22114fa701..2282f24417 100644 --- a/cpukit/libblock/src/bdbuf.c +++ b/cpukit/libblock/src/bdbuf.c @@ -123,7 +123,9 @@ typedef struct rtems_bdbuf_cache rtems_chain_control modified; /**< Modified buffers list */ rtems_chain_control sync; /**< Buffers to sync list */ - rtems_bdbuf_waiters access_waiters; /**< Wait for a buffer in ACCESS + rtems_bdbuf_waiters access_waiters; /**< Wait for a buffer in + * ACCESS_CACHED, ACCESS_MODIFIED or + * ACCESS_EMPTY * state. */ rtems_bdbuf_waiters transfer_waiters; /**< Wait for a buffer in TRANSFER * state. */ @@ -142,7 +144,6 @@ typedef struct rtems_bdbuf_cache #define RTEMS_BLKDEV_FATAL_ERROR(n) \ (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF)) -#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_3 RTEMS_BLKDEV_FATAL_ERROR(1) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_4 RTEMS_BLKDEV_FATAL_ERROR(2) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_5 RTEMS_BLKDEV_FATAL_ERROR(3) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_6 RTEMS_BLKDEV_FATAL_ERROR(4) @@ -150,7 +151,7 @@ typedef struct rtems_bdbuf_cache #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_8 RTEMS_BLKDEV_FATAL_ERROR(6) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_9 RTEMS_BLKDEV_FATAL_ERROR(7) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_10 RTEMS_BLKDEV_FATAL_ERROR(8) -#define RTEMS_BLKDEV_FATAL_BDBUF_CACHE_RM RTEMS_BLKDEV_FATAL_ERROR(9) +#define RTEMS_BLKDEV_FATAL_BDBUF_TREE_RM RTEMS_BLKDEV_FATAL_ERROR(9) #define RTEMS_BLKDEV_FATAL_BDBUF_SWAPOUT RTEMS_BLKDEV_FATAL_ERROR(10) #define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK RTEMS_BLKDEV_FATAL_ERROR(11) #define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(12) @@ -1054,15 +1055,15 @@ rtems_bdbuf_add_to_modified_list_after_access (rtems_bdbuf_buffer *bd) * modified list. Resetting the timer on each access which could result in a * buffer never getting to 0 and never being forced onto disk. This raises a * difficult question. Is a snapshot of a block that is changing better than - * nothing being written ? We have tended to think we should hold changes for + * nothing being written? We have tended to think we should hold changes for * only a specific period of time even if still changing and get onto disk * and letting the file system try and recover this position if it can. */ - if (bd->state == RTEMS_BDBUF_STATE_ACCESS) + if (bd->state == RTEMS_BDBUF_STATE_ACCESS_CACHED + || bd->state == RTEMS_BDBUF_STATE_ACCESS_EMPTY) bd->hold_timer = bdbuf_config.swap_block_hold; rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_MODIFIED); - rtems_chain_append (&bdbuf_cache.modified, &bd->link); if (bd->waiters) @@ -1075,9 +1076,7 @@ static void rtems_bdbuf_add_to_lru_list_after_access (rtems_bdbuf_buffer *bd) { rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED); - rtems_chain_append (&bdbuf_cache.lru, &bd->link); - rtems_bdbuf_group_release (bd); if (bd->waiters) @@ -1122,15 +1121,21 @@ rtems_bdbuf_bds_per_group (size_t size) } static void -rtems_bdbuf_remove_from_cache_and_lru_list (rtems_bdbuf_buffer *bd) +rtems_bdbuf_remove_from_tree (rtems_bdbuf_buffer *bd) +{ + if (rtems_bdbuf_avl_remove (&bdbuf_cache.tree, bd) != 0) + rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_TREE_RM); +} + +static void +rtems_bdbuf_remove_from_tree_and_lru_list (rtems_bdbuf_buffer *bd) { switch (bd->state) { - case RTEMS_BDBUF_STATE_EMPTY: + case RTEMS_BDBUF_STATE_FREE: break; case RTEMS_BDBUF_STATE_CACHED: - if (rtems_bdbuf_avl_remove (&bdbuf_cache.tree, bd) != 0) - rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_3); + rtems_bdbuf_remove_from_tree (bd); break; default: rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_10); @@ -1139,11 +1144,37 @@ rtems_bdbuf_remove_from_cache_and_lru_list (rtems_bdbuf_buffer *bd) rtems_chain_extract (&bd->link); } +static void +rtems_bdbuf_make_free_and_add_to_lru_list (rtems_bdbuf_buffer *bd) +{ + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_FREE); + rtems_chain_prepend (&bdbuf_cache.lru, &bd->link); +} + static void rtems_bdbuf_make_empty_and_add_to_lru_list (rtems_bdbuf_buffer *bd) { rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY); - rtems_chain_prepend (&bdbuf_cache.lru, &bd->link); + rtems_chain_append (&bdbuf_cache.lru, &bd->link); +} + +static void +rtems_bdbuf_release_empty_buffer (rtems_bdbuf_buffer *bd) +{ + rtems_bdbuf_group_release (bd); + + if (bd->waiters) + { + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY); + rtems_chain_append (&bdbuf_cache.lru, &bd->link); + rtems_bdbuf_wake (&bdbuf_cache.access_waiters); + } + else + { + rtems_bdbuf_remove_from_tree (bd); + rtems_bdbuf_make_free_and_add_to_lru_list (bd); + rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters); + } } /** @@ -1172,7 +1203,7 @@ rtems_bdbuf_group_realloc (rtems_bdbuf_group* group, size_t new_bds_per_group) for (b = 0, bd = group->bdbuf; b < group->bds_per_group; b++, bd += bufs_per_bd) - rtems_bdbuf_remove_from_cache_and_lru_list (bd); + rtems_bdbuf_remove_from_tree_and_lru_list (bd); group->bds_per_group = new_bds_per_group; bufs_per_bd = bdbuf_cache.max_bds_per_group / new_bds_per_group; @@ -1180,7 +1211,7 @@ rtems_bdbuf_group_realloc (rtems_bdbuf_group* group, size_t new_bds_per_group) for (b = 1, bd = group->bdbuf + bufs_per_bd; b < group->bds_per_group; b++, bd += bufs_per_bd) - rtems_bdbuf_make_empty_and_add_to_lru_list (bd); + rtems_bdbuf_make_free_and_add_to_lru_list (bd); if (b > 1) rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters); @@ -1193,17 +1224,16 @@ rtems_bdbuf_recycle_buffer (rtems_bdbuf_buffer *bd, dev_t dev, rtems_blkdev_bnum block) { - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_FRESH); - bd->dev = dev; bd->block = block; bd->avl.left = NULL; bd->avl.right = NULL; - bd->error = 0; bd->waiters = 0; if (rtems_bdbuf_avl_insert (&bdbuf_cache.tree, bd) != 0) rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_RECYCLE); + + rtems_bdbuf_make_empty_and_add_to_lru_list (bd); } static rtems_bdbuf_buffer * @@ -1231,7 +1261,7 @@ rtems_bdbuf_get_buffer_from_lru_list (dev_t dev, { if (bd->group->bds_per_group == bds_per_group) { - rtems_bdbuf_remove_from_cache_and_lru_list (bd); + rtems_bdbuf_remove_from_tree_and_lru_list (bd); recycle_bd = bd; } @@ -1489,16 +1519,16 @@ rtems_bdbuf_wait_for_access (rtems_bdbuf_buffer *bd) { switch (bd->state) { - case RTEMS_BDBUF_STATE_FRESH: - return; case RTEMS_BDBUF_STATE_MODIFIED: rtems_bdbuf_group_release (bd); /* Fall through */ case RTEMS_BDBUF_STATE_CACHED: + case RTEMS_BDBUF_STATE_EMPTY: rtems_chain_extract (&bd->link); return; + case RTEMS_BDBUF_STATE_ACCESS_CACHED: + case RTEMS_BDBUF_STATE_ACCESS_EMPTY: case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: - case RTEMS_BDBUF_STATE_ACCESS: rtems_bdbuf_wait (bd, &bdbuf_cache.access_waiters); break; case RTEMS_BDBUF_STATE_TRANSFER: @@ -1533,12 +1563,13 @@ rtems_bdbuf_wait_for_recycle (rtems_bdbuf_buffer *bd) { switch (bd->state) { - case RTEMS_BDBUF_STATE_EMPTY: + case RTEMS_BDBUF_STATE_FREE: return true; case RTEMS_BDBUF_STATE_MODIFIED: rtems_bdbuf_request_sync_for_modified_buffer (bd); break; case RTEMS_BDBUF_STATE_CACHED: + case RTEMS_BDBUF_STATE_EMPTY: if (bd->waiters == 0) return true; else @@ -1552,8 +1583,9 @@ rtems_bdbuf_wait_for_recycle (rtems_bdbuf_buffer *bd) rtems_bdbuf_anonymous_wait (&bdbuf_cache.buffer_waiters); return false; } + case RTEMS_BDBUF_STATE_ACCESS_CACHED: + case RTEMS_BDBUF_STATE_ACCESS_EMPTY: case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: - case RTEMS_BDBUF_STATE_ACCESS: rtems_bdbuf_wait (bd, &bdbuf_cache.access_waiters); break; case RTEMS_BDBUF_STATE_TRANSFER: @@ -1564,8 +1596,6 @@ rtems_bdbuf_wait_for_recycle (rtems_bdbuf_buffer *bd) rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_8); } } - - return true; } static void @@ -1576,8 +1606,10 @@ rtems_bdbuf_wait_for_sync_done (rtems_bdbuf_buffer *bd) switch (bd->state) { case RTEMS_BDBUF_STATE_CACHED: + case RTEMS_BDBUF_STATE_EMPTY: case RTEMS_BDBUF_STATE_MODIFIED: - case RTEMS_BDBUF_STATE_ACCESS: + case RTEMS_BDBUF_STATE_ACCESS_CACHED: + case RTEMS_BDBUF_STATE_ACCESS_EMPTY: case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: return; case RTEMS_BDBUF_STATE_SYNC: @@ -1642,8 +1674,8 @@ rtems_bdbuf_get_buffer_for_access (dev_t dev, { if (rtems_bdbuf_wait_for_recycle (bd)) { - rtems_bdbuf_remove_from_cache_and_lru_list (bd); - rtems_bdbuf_make_empty_and_add_to_lru_list (bd); + rtems_bdbuf_remove_from_tree_and_lru_list (bd); + rtems_bdbuf_make_free_and_add_to_lru_list (bd); rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters); } bd = NULL; @@ -1760,8 +1792,10 @@ rtems_bdbuf_get (dev_t dev, switch (bd->state) { case RTEMS_BDBUF_STATE_CACHED: - case RTEMS_BDBUF_STATE_FRESH: - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS); + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_CACHED); + break; + case RTEMS_BDBUF_STATE_EMPTY: + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_EMPTY); break; case RTEMS_BDBUF_STATE_MODIFIED: /* @@ -1801,24 +1835,23 @@ rtems_bdbuf_get (dev_t dev, * structure (in this case - pointer to the appropriate * block device request structure). * @param status I/O completion status - * @param error errno error code if status != RTEMS_SUCCESSFUL */ static void -rtems_bdbuf_read_done (void* arg, rtems_status_code status, int error) +rtems_bdbuf_transfer_done (void* arg, rtems_status_code status) { rtems_blkdev_request* req = (rtems_blkdev_request*) arg; - req->error = error; req->status = status; rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); } static void -rtems_bdbuf_create_read_request (rtems_blkdev_request *req, - rtems_disk_device *dd, - rtems_blkdev_bnum media_block, - size_t bds_per_group) +rtems_bdbuf_create_read_request (const rtems_disk_device *dd, + rtems_blkdev_bnum media_block, + size_t bds_per_group, + rtems_blkdev_request *req, + rtems_bdbuf_buffer **bd_ptr) { rtems_bdbuf_buffer *bd = NULL; rtems_blkdev_bnum media_block_end = dd->start + dd->size; @@ -1831,10 +1864,17 @@ rtems_bdbuf_create_read_request (rtems_blkdev_request *req, if (media_block_end - media_block < transfer_count) transfer_count = media_block_end - media_block; + req->req = RTEMS_BLKDEV_REQ_READ; + req->req_done = rtems_bdbuf_transfer_done; + req->done_arg = req; + req->io_task = rtems_task_self (); + req->status = RTEMS_RESOURCE_IN_USE; req->bufnum = 0; bd = rtems_bdbuf_get_buffer_for_access (dev, media_block, bds_per_group); + *bd_ptr = bd; + req->bufs [0].user = bd; req->bufs [0].block = media_block; req->bufs [0].length = block_size; @@ -1848,7 +1888,7 @@ rtems_bdbuf_create_read_request (rtems_blkdev_request *req, case RTEMS_BDBUF_STATE_CACHED: case RTEMS_BDBUF_STATE_MODIFIED: return; - case RTEMS_BDBUF_STATE_FRESH: + case RTEMS_BDBUF_STATE_EMPTY: rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); break; default: @@ -1882,96 +1922,76 @@ rtems_bdbuf_create_read_request (rtems_blkdev_request *req, req->bufnum = transfer_index; } -static rtems_bdbuf_buffer * -rtems_bdbuf_execute_read_request (rtems_blkdev_request *req, - rtems_disk_device *dd) +static rtems_status_code +rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd, + rtems_blkdev_request *req, + bool cache_locked) { - if (req->bufnum) - { - /* - * Unlock the cache. We have the buffer for the block and it will be in the - * access or transfer state. We may also have a number of read ahead blocks - * if we need to transfer data. At this point any other threads can gain - * access to the cache and if they are after any of the buffers we have - * they will block and be woken when the buffer is returned to the cache. - * - * If a transfer is needed the I/O operation will occur with pre-emption - * enabled and the cache unlocked. This is a change to the previous version - * of the bdbuf code. - */ - int result = 0; - int error = 0; - uint32_t transfer_index = 0; - bool wake_transfer = false; - bool wake_buffer = false; + rtems_status_code sc = RTEMS_SUCCESSFUL; + int result = 0; + uint32_t transfer_index = 0; + bool wake_transfer = false; + bool wake_buffer = false; + if (cache_locked) rtems_bdbuf_unlock_cache (); - req->req = RTEMS_BLKDEV_REQ_READ; - req->req_done = rtems_bdbuf_read_done; - req->done_arg = req; - req->io_task = rtems_task_self (); - req->status = RTEMS_RESOURCE_IN_USE; - req->error = 0; + result = dd->ioctl (dd->phys_dev, RTEMS_BLKIO_REQUEST, req); - result = dd->ioctl (dd->phys_dev, RTEMS_BLKIO_REQUEST, req); + if (result == 0) + { + rtems_bdbuf_wait_for_event (RTEMS_BDBUF_TRANSFER_SYNC); + sc = req->status; + } + else + sc = RTEMS_IO_ERROR; - if (result == 0) - { - rtems_bdbuf_wait_for_event (RTEMS_BDBUF_TRANSFER_SYNC); - error = req->error; - } + rtems_bdbuf_lock_cache (); + + for (transfer_index = 0; transfer_index < req->bufnum; ++transfer_index) + { + rtems_bdbuf_buffer *bd = req->bufs [transfer_index].user; + bool waiters = bd->waiters > 0; + + if (waiters) + wake_transfer = true; else - error = errno; + wake_buffer = true; - rtems_bdbuf_lock_cache (); + rtems_bdbuf_group_release (bd); - for (transfer_index = 0; transfer_index < req->bufnum; ++transfer_index) + if (sc == RTEMS_SUCCESSFUL) { - rtems_bdbuf_buffer *bd = req->bufs [transfer_index].user; - bool waiters = bd->waiters; - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED); + rtems_chain_append (&bdbuf_cache.lru, &bd->link); + } + else if (waiters) + { + rtems_bdbuf_make_empty_and_add_to_lru_list (bd); + } + else + { + rtems_bdbuf_remove_from_tree (bd); + rtems_bdbuf_make_free_and_add_to_lru_list (bd); + } - if (waiters) - wake_transfer = true; - - bd->error = error; - - if (rtems_bdbuf_tracer) - rtems_bdbuf_show_users ("read-ahead", bd); - - if (transfer_index > 0) - { - /* - * This is a read ahead buffer. - */ - - rtems_bdbuf_group_release (bd); + if (rtems_bdbuf_tracer) + rtems_bdbuf_show_users ("transfer", bd); + } - if (!waiters) - wake_buffer = true; + if (wake_transfer) + rtems_bdbuf_wake (&bdbuf_cache.transfer_waiters); - if (error == 0 || waiters) - rtems_chain_append (&bdbuf_cache.lru, &bd->link); - else - { - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY); - rtems_chain_prepend (&bdbuf_cache.lru, &bd->link); - if (rtems_bdbuf_avl_remove (&bdbuf_cache.tree, bd) != 0) - rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CACHE_RM); - } - } - } - - if (wake_transfer) - rtems_bdbuf_wake (&bdbuf_cache.transfer_waiters); + if (wake_buffer) + rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters); - if (wake_buffer) - rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters); - } + if (!cache_locked) + rtems_bdbuf_unlock_cache (); - return req->bufs [0].user; + if (sc == RTEMS_SUCCESSFUL || sc == RTEMS_UNSATISFIED) + return sc; + else + return RTEMS_IO_ERROR; } rtems_status_code @@ -1981,8 +2001,8 @@ rtems_bdbuf_read (dev_t dev, { rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_disk_device *dd = NULL; - rtems_bdbuf_buffer *bd = NULL; rtems_blkdev_request *req = NULL; + rtems_bdbuf_buffer *bd = NULL; rtems_blkdev_bnum media_block = 0; size_t bds_per_group = 0; @@ -2004,35 +2024,48 @@ rtems_bdbuf_read (dev_t dev, media_block + dd->start, block, (unsigned) dev); rtems_bdbuf_lock_cache (); - rtems_bdbuf_create_read_request (req, dd, media_block, bds_per_group); + rtems_bdbuf_create_read_request (dd, media_block, bds_per_group, req, &bd); - bd = rtems_bdbuf_execute_read_request (req, dd); - - switch (bd->state) + if (req->bufnum > 0) { - case RTEMS_BDBUF_STATE_CACHED: - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS); - break; - case RTEMS_BDBUF_STATE_MODIFIED: - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_MODIFIED); - break; - default: - rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_4); - break; + sc = rtems_bdbuf_execute_transfer_request (dd, req, true); + if (sc == RTEMS_SUCCESSFUL) + { + rtems_chain_extract (&bd->link); + rtems_bdbuf_group_obtain (bd); + } } - if (rtems_bdbuf_tracer) + if (sc == RTEMS_SUCCESSFUL) { - rtems_bdbuf_show_users ("read", bd); - rtems_bdbuf_show_usage (); + switch (bd->state) + { + case RTEMS_BDBUF_STATE_CACHED: + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_CACHED); + break; + case RTEMS_BDBUF_STATE_MODIFIED: + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_MODIFIED); + break; + default: + rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_4); + break; + } + + if (rtems_bdbuf_tracer) + { + rtems_bdbuf_show_users ("read", bd); + rtems_bdbuf_show_usage (); + } + + *bd_ptr = bd; } + else + *bd_ptr = NULL; rtems_bdbuf_unlock_cache (); rtems_bdbuf_release_disk (dd); - *bd_ptr = bd; - - return RTEMS_SUCCESSFUL; + return sc; } static rtems_status_code @@ -2063,9 +2096,12 @@ rtems_bdbuf_release (rtems_bdbuf_buffer *bd) switch (bd->state) { - case RTEMS_BDBUF_STATE_ACCESS: + case RTEMS_BDBUF_STATE_ACCESS_CACHED: rtems_bdbuf_add_to_lru_list_after_access (bd); break; + case RTEMS_BDBUF_STATE_ACCESS_EMPTY: + rtems_bdbuf_release_empty_buffer (bd); + break; case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: rtems_bdbuf_add_to_modified_list_after_access (bd); break; @@ -2093,7 +2129,8 @@ rtems_bdbuf_release_modified (rtems_bdbuf_buffer *bd) switch (bd->state) { - case RTEMS_BDBUF_STATE_ACCESS: + case RTEMS_BDBUF_STATE_ACCESS_CACHED: + case RTEMS_BDBUF_STATE_ACCESS_EMPTY: case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: rtems_bdbuf_add_to_modified_list_after_access (bd); break; @@ -2121,7 +2158,8 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer *bd) switch (bd->state) { - case RTEMS_BDBUF_STATE_ACCESS: + case RTEMS_BDBUF_STATE_ACCESS_CACHED: + case RTEMS_BDBUF_STATE_ACCESS_EMPTY: case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: rtems_bdbuf_add_to_sync_list_after_access (bd); break; @@ -2140,8 +2178,17 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer *bd) * If no one intercepts the sync, we created a cached buffer which may be * recycled. */ - if (bd->state == RTEMS_BDBUF_STATE_CACHED && bd->waiters == 0) + if (bd->waiters == 0 + && (bd->state == RTEMS_BDBUF_STATE_CACHED + || bd->state == RTEMS_BDBUF_STATE_EMPTY)) + { + if (bd->state == RTEMS_BDBUF_STATE_EMPTY) + { + rtems_bdbuf_remove_from_tree (bd); + rtems_bdbuf_make_free_and_add_to_lru_list (bd); + } rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters); + } rtems_bdbuf_unlock_cache (); @@ -2190,25 +2237,10 @@ rtems_bdbuf_syncdev (dev_t dev) return RTEMS_SUCCESSFUL; } -/** - * Call back handler called by the low level driver when the transfer has - * completed. This function may be invoked from interrupt handlers. - * - * @param arg Arbitrary argument specified in block device request - * structure (in this case - pointer to the appropriate - * block device request structure). - * @param status I/O completion status - * @param error errno error code if status != RTEMS_SUCCESSFUL - */ -static void -rtems_bdbuf_write_done(void *arg, rtems_status_code status, int error) +static int +rtems_bdbuf_null_disk_ioctl (rtems_disk_device *dd, uint32_t req, void *arg) { - rtems_blkdev_request* req = (rtems_blkdev_request*) arg; - - req->error = error; - req->status = status; - - rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); + return -1; } /** @@ -2221,7 +2253,10 @@ rtems_bdbuf_write_done(void *arg, rtems_status_code status, int error) static void rtems_bdbuf_swapout_write (rtems_bdbuf_swapout_transfer* transfer) { - rtems_disk_device* dd; + static rtems_disk_device null_disk = { + .capabilities = 0, + .ioctl = rtems_bdbuf_null_disk_ioctl + }; if (rtems_bdbuf_tracer) printf ("bdbuf:swapout transfer: %08x\n", (unsigned) transfer->dev); @@ -2232,166 +2267,99 @@ rtems_bdbuf_swapout_write (rtems_bdbuf_swapout_transfer* transfer) if (!rtems_chain_is_empty (&transfer->bds)) { /* - * Obtain the disk device. The cache's mutex has been released to avoid a - * dead lock. + * The last block number used when the driver only supports + * continuous blocks in a single request. */ - dd = rtems_disk_obtain (transfer->dev); - if (dd) - { - /* - * The last block number used when the driver only supports - * continuous blocks in a single request. - */ - uint32_t last_block = 0; - - /* - * Number of buffers per bd. This is used to detect the next - * block. - */ - uint32_t bufs_per_bd = dd->block_size / bdbuf_config.buffer_min; - - /* - * Take as many buffers as configured and pass to the driver. Note, the - * API to the drivers has an array of buffers and if a chain was passed - * we could have just passed the list. If the driver API is updated it - * should be possible to make this change with little effect in this - * code. The array that is passed is broken in design and should be - * removed. Merging members of a struct into the first member is - * trouble waiting to happen. - */ - transfer->write_req->status = RTEMS_RESOURCE_IN_USE; - transfer->write_req->error = 0; - transfer->write_req->bufnum = 0; - - while (!rtems_chain_is_empty (&transfer->bds)) - { - rtems_bdbuf_buffer* bd = - (rtems_bdbuf_buffer*) rtems_chain_get (&transfer->bds); - - bool write = false; - - /* - * If the device only accepts sequential buffers and this is not the - * first buffer (the first is always sequential, and the buffer is not - * sequential then put the buffer back on the transfer chain and write - * the committed buffers. - */ - - if (rtems_bdbuf_tracer) - printf ("bdbuf:swapout write: bd:%" PRIu32 ", bufnum:%" PRIu32 " mode:%s\n", - bd->block, transfer->write_req->bufnum, - dd->phys_dev->capabilities & - RTEMS_BLKDEV_CAP_MULTISECTOR_CONT ? "MULIT" : "SCAT"); - - if ((dd->phys_dev->capabilities & RTEMS_BLKDEV_CAP_MULTISECTOR_CONT) && - transfer->write_req->bufnum && - (bd->block != (last_block + bufs_per_bd))) - { - rtems_chain_prepend (&transfer->bds, &bd->link); - write = true; - } - else - { - rtems_blkdev_sg_buffer* buf; - buf = &transfer->write_req->bufs[transfer->write_req->bufnum]; - transfer->write_req->bufnum++; - buf->user = bd; - buf->block = bd->block; - buf->length = dd->block_size; - buf->buffer = bd->buffer; - last_block = bd->block; - } + uint32_t last_block = 0; - /* - * Perform the transfer if there are no more buffers, or the transfer - * size has reached the configured max. value. - */ - - if (rtems_chain_is_empty (&transfer->bds) || - (transfer->write_req->bufnum >= bdbuf_config.max_write_blocks)) - write = true; + /* + * Number of buffers per bd. This is used to detect the next + * block. + */ + uint32_t bufs_per_bd = 0; - if (write) - { - int result; - uint32_t b; + /* + * Obtain the disk device. The cache's mutex has been released to avoid a + * dead lock. + */ + rtems_disk_device *dd = rtems_disk_obtain (transfer->dev); - if (rtems_bdbuf_tracer) - printf ("bdbuf:swapout write: writing bufnum:%" PRIu32 "\n", - transfer->write_req->bufnum); + if (dd == NULL) + dd = &null_disk; - /* - * Perform the transfer. No cache locks, no preemption, only the disk - * device is being held. - */ - result = dd->ioctl (dd->phys_dev, RTEMS_BLKIO_REQUEST, - transfer->write_req); - if (result < 0) - { - rtems_bdbuf_lock_cache (); + bufs_per_bd = dd->block_size / bdbuf_config.buffer_min; - for (b = 0; b < transfer->write_req->bufnum; b++) - { - bd = transfer->write_req->bufs[b].user; - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_MODIFIED); - bd->error = errno; - - /* - * Place back on the cache's modified queue and try again. - * - * @warning Not sure this is the best option but I do not know - * what else can be done. - */ - rtems_chain_append (&bdbuf_cache.modified, &bd->link); - } - } - else - { - rtems_bdbuf_wait_for_event (RTEMS_BDBUF_TRANSFER_SYNC); - - rtems_bdbuf_lock_cache (); + /* + * Take as many buffers as configured and pass to the driver. Note, the + * API to the drivers has an array of buffers and if a chain was passed + * we could have just passed the list. If the driver API is updated it + * should be possible to make this change with little effect in this + * code. The array that is passed is broken in design and should be + * removed. Merging members of a struct into the first member is + * trouble waiting to happen. + */ + transfer->write_req->status = RTEMS_RESOURCE_IN_USE; + transfer->write_req->bufnum = 0; - for (b = 0; b < transfer->write_req->bufnum; b++) - { - bd = transfer->write_req->bufs[b].user; - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED); - bd->error = 0; + while (!rtems_chain_is_empty (&transfer->bds)) + { + rtems_bdbuf_buffer* bd = + (rtems_bdbuf_buffer*) rtems_chain_get (&transfer->bds); - rtems_bdbuf_group_release (bd); + bool write = false; - if (rtems_bdbuf_tracer) - rtems_bdbuf_show_users ("write", bd); + /* + * If the device only accepts sequential buffers and this is not the + * first buffer (the first is always sequential, and the buffer is not + * sequential then put the buffer back on the transfer chain and write + * the committed buffers. + */ - rtems_chain_append (&bdbuf_cache.lru, &bd->link); + if (rtems_bdbuf_tracer) + printf ("bdbuf:swapout write: bd:%" PRIu32 ", bufnum:%" PRIu32 " mode:%s\n", + bd->block, transfer->write_req->bufnum, + dd->phys_dev->capabilities & + RTEMS_BLKDEV_CAP_MULTISECTOR_CONT ? "MULIT" : "SCAT"); + + if ((dd->phys_dev->capabilities & RTEMS_BLKDEV_CAP_MULTISECTOR_CONT) && + transfer->write_req->bufnum && + (bd->block != (last_block + bufs_per_bd))) + { + rtems_chain_prepend (&transfer->bds, &bd->link); + write = true; + } + else + { + rtems_blkdev_sg_buffer* buf; + buf = &transfer->write_req->bufs[transfer->write_req->bufnum]; + transfer->write_req->bufnum++; + buf->user = bd; + buf->block = bd->block; + buf->length = dd->block_size; + buf->buffer = bd->buffer; + last_block = bd->block; + } - if (bd->waiters) - rtems_bdbuf_wake (&bdbuf_cache.transfer_waiters); - else - rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters); - } - } + /* + * Perform the transfer if there are no more buffers, or the transfer + * size has reached the configured max. value. + */ - if (rtems_bdbuf_tracer) - rtems_bdbuf_show_usage (); + if (rtems_chain_is_empty (&transfer->bds) || + (transfer->write_req->bufnum >= bdbuf_config.max_write_blocks)) + write = true; - rtems_bdbuf_unlock_cache (); + if (write) + { + rtems_bdbuf_execute_transfer_request (dd, transfer->write_req, false); - transfer->write_req->status = RTEMS_RESOURCE_IN_USE; - transfer->write_req->error = 0; - transfer->write_req->bufnum = 0; - } + transfer->write_req->status = RTEMS_RESOURCE_IN_USE; + transfer->write_req->bufnum = 0; } + } + if (dd != &null_disk) rtems_disk_release (dd); - } - else - { - /* - * We have buffers but no device. Put the BDs back onto the - * ready queue and exit. - */ - /* @todo fixme */ - } } } @@ -2644,7 +2612,7 @@ rtems_bdbuf_swapout_writereq_alloc (void) rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM); write_req->req = RTEMS_BLKDEV_REQ_WRITE; - write_req->req_done = rtems_bdbuf_write_done; + write_req->req_done = rtems_bdbuf_transfer_done; write_req->done_arg = write_req; write_req->io_task = rtems_task_self (); diff --git a/cpukit/libblock/src/flashdisk.c b/cpukit/libblock/src/flashdisk.c index 79f860126d..a1c8ea5036 100644 --- a/cpukit/libblock/src/flashdisk.c +++ b/cpukit/libblock/src/flashdisk.c @@ -2071,8 +2071,7 @@ rtems_fdisk_read (rtems_flashdisk* fd, rtems_blkdev_request* req) } } - req->req_done (req->done_arg, - ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR, ret); + req->req_done (req->done_arg, ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR); return ret; } @@ -2107,8 +2106,7 @@ rtems_fdisk_write (rtems_flashdisk* fd, rtems_blkdev_request* req) } } - req->req_done (req->done_arg, - ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR, ret); + req->req_done (req->done_arg, ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR); return 0; } diff --git a/cpukit/libblock/src/nvdisk.c b/cpukit/libblock/src/nvdisk.c index 3aaf543853..fde4a025d9 100644 --- a/cpukit/libblock/src/nvdisk.c +++ b/cpukit/libblock/src/nvdisk.c @@ -595,8 +595,7 @@ rtems_nvdisk_read (rtems_nvdisk* nvd, rtems_blkdev_request* req) } } - req->req_done (req->done_arg, - ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR, ret); + req->req_done (req->done_arg, ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR); return ret; } @@ -635,8 +634,7 @@ rtems_nvdisk_write (rtems_nvdisk* nvd, rtems_blkdev_request* req) } } - req->req_done (req->done_arg, - ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR, ret); + req->req_done (req->done_arg, ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR); return 0; } diff --git a/cpukit/libblock/src/ramdisk-driver.c b/cpukit/libblock/src/ramdisk-driver.c index 9defff623d..1e078fdf2a 100644 --- a/cpukit/libblock/src/ramdisk-driver.c +++ b/cpukit/libblock/src/ramdisk-driver.c @@ -65,7 +65,7 @@ ramdisk_read(struct ramdisk *rd, rtems_blkdev_request *req) #endif memcpy(sg->buffer, from + (sg->block * rd->block_size), sg->length); } - req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0); + req->req_done(req->done_arg, RTEMS_SUCCESSFUL); return 0; } @@ -89,7 +89,7 @@ ramdisk_write(struct ramdisk *rd, rtems_blkdev_request *req) #endif memcpy(to + (sg->block * rd->block_size), sg->buffer, sg->length); } - req->req_done(req->done_arg, RTEMS_SUCCESSFUL, 0); + req->req_done(req->done_arg, RTEMS_SUCCESSFUL); return 0; } -- cgit v1.2.3