diff options
Diffstat (limited to 'include/rtems/flashdisk.h')
-rw-r--r-- | include/rtems/flashdisk.h | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/include/rtems/flashdisk.h b/include/rtems/flashdisk.h new file mode 100644 index 0000000000..ec353096ad --- /dev/null +++ b/include/rtems/flashdisk.h @@ -0,0 +1,460 @@ +/** + * @file + * + * @ingroup RTEMSFDisk + * + * @brief Interface to a Flash Disk Block Device + * + * This file defines the interface to a flash disk block device. + */ + +/* + * Copyright (C) 2007 Chris Johns + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#if !defined (_RTEMS_FLASHDISK_H_) +#define _RTEMS_FLASHDISK_H_ + +#include <stdint.h> +#include <sys/ioctl.h> + +#include <rtems.h> + +/** + * @defgroup RTEMSFDisk Flash Disk Device + * + * @ingroup rtems_blkdev + * + * Flash disk driver for RTEMS provides support for block based + * file systems on flash devices. The driver is not a flash file + * system nor does it try to compete with flash file systems. It + * currently does not journal how-ever block sequence numbering + * could be added to allow recovery of a past positions if + * a power down occurred while being updated. + * + * This flash driver provides block device support for most flash + * devices. The driver has been tested on NOR type devices such + * as the AMLV160 or M28W160. Support for NAND type devices may + * require driver changes to allow speedy recover of the block + * mapping data and to also handle the current use of word programming. + * Currently the page descriptors are stored in the first few pages + * of each segment. + * + * The driver supports devices, segments and pages. You provide + * to the driver the device descriptions as a table of device + * descriptors. Each device descriptor contain a table of + * segment descriptions or segment descriptors. The driver uses + * this information to manage the devices. + * + * A device is made up of segments. These are also called + * sectors or blocks. It is the smallest erasable part of a device. + * A device can have differing size segments at different + * offsets in the device. The segment descriptors support repeating + * segments that are continuous in the device. The driver breaks the + * segments up into pages. The first pages of a segment contain + * the page descriptors. A page descriptor hold the page flags, + * a CRC for the page of data and the block number the page + * holds. The block can appear in any order in the devices. A + * page is active if it hold a current block of data. If the + * used bit is set the page is counted as used. A page moves + * from erased to active to used then back to erased. If a block + * is written that is already in a page, the block is written to + * a new page the old page is flagged as used. + * + * At initialization time each segment's page descriptors are + * read into memory and scanned to determine the active pages, + * the used pages and the bad pages. If a segment has any erased + * pages it is queue on the available queue. If the segment has + * no erased pages it is queue on the used queue. + * + * The available queue is sorted from the least number available + * to the most number of available pages. A segment that has just + * been erased will placed at the end of the queue. A segment that + * has only a few available pages will be used sooner and once + * there are no available pages it is queued on the used queue. + * The used queue hold segments that have no available pages and + * is sorted from the least number of active pages to the most + * number of active pages. + * + * The driver is required to compact segments. Compacting takes + * the segment with the most number of available pages from the + * available queue then takes segments with the least number of + * active pages from the used queue until it has enough pages + * to fill the empty segment. As the active pages are moved + * they flagged as used and once the segment has only used pages + * it is erased. + * + * A flash block driver like this never knows if a page is not + * being used by the file-system. A typical file system is not + * design with the idea of erasing a block on a disk once it is + * not being used. The file-system will normally use a flag + * or a location as a marker to say that part of the disk is + * no longer in use. This means a number of blocks could be + * held in active pages but are no in use by the file system. + * The file system may also read blocks that have never been + * written to disk. This complicates the driver and may make + * the wear, usage and erase patterns harsher than a flash + * file system. The driver may also suffer from problems if + * power is lost. + * + * There are some flash disk specific IO control request types. + * To use open the device and issue the ioctl() call. + * + * @code + * int fd = open ("/dev/flashdisk0", O_WRONLY, 0); + * if (fd < 0) + * { + * printf ("driver open failed: %s\n", strerror (errno)); + * exit (1); + * } + * if (ioctl (fd, RTEMS_FDISK_IOCTL_ERASE_DISK) < 0) + * { + * printf ("driver erase failed: %s\n", strerror (errno)); + * exit (1); + * } + * close (fd); + * @endcode + */ +/**@{**/ + +/** + * @brief The base name of the flash disks. + */ +#define RTEMS_FLASHDISK_DEVICE_BASE_NAME "/dev/fdd" + +#define RTEMS_FDISK_IOCTL_ERASE_DISK _IO('B', 128) +#define RTEMS_FDISK_IOCTL_COMPACT _IO('B', 129) +#define RTEMS_FDISK_IOCTL_ERASE_USED _IO('B', 130) +#define RTEMS_FDISK_IOCTL_MONITORING _IO('B', 131) +#define RTEMS_FDISK_IOCTL_INFO_LEVEL _IO('B', 132) +#define RTEMS_FDISK_IOCTL_PRINT_STATUS _IO('B', 133) + +/** + * @brief Flash Disk Monitoring Data allows a user to obtain + * the current status of the disk. + */ +typedef struct rtems_fdisk_monitor_data +{ + uint32_t block_size; + uint32_t block_count; + uint32_t unavail_blocks; + uint32_t device_count; + uint32_t segment_count; + uint32_t page_count; + uint32_t blocks_used; + uint32_t segs_available; + uint32_t segs_used; + uint32_t segs_failed; + uint32_t seg_erases; + uint32_t pages_desc; + uint32_t pages_active; + uint32_t pages_used; + uint32_t pages_bad; + uint32_t info_level; +} rtems_fdisk_monitor_data; + +/** + * @brief Flash Segment Descriptor holds, number of continuous segments in the + * device of this type, the base segment number in the device, the address + * offset of the base segment in the device, and the size of segment. + * + * Typically this structure is part of a table of segments in the + * device which is referenced in the flash disk configuration table. + * The reference is kept in the driver and used all the time to + * manage the flash device, therefore it must always exist. + */ +typedef struct rtems_fdisk_segment_desc +{ + uint16_t count; /**< Number of segments of this type in a row. */ + uint16_t segment; /**< The base segment number. */ + uint32_t offset; /**< Address offset of base segment in device. */ + uint32_t size; /**< Size of the segment in bytes. */ +} rtems_fdisk_segment_desc; + +/** + * @brief Return the number of kilo-bytes. + */ +#define RTEMS_FDISK_KBYTES(_k) (UINT32_C(1024) * (_k)) + +/** + * Forward declaration of the device descriptor. + */ +struct rtems_fdisk_device_desc; + +/** + * @brief Flash Low Level driver handlers. + * + * Typically this structure is part of a table of handlers in the + * device which is referenced in the flash disk configuration table. + * The reference is kept in the driver and used all the time to + * manage the flash device, therefore it must always exist. + */ +typedef struct rtems_fdisk_driver_handlers +{ + /** + * Read data from the device into the buffer. Return an errno + * error number if the device cannot be read. A segment descriptor + * can describe more than one segment in a device if the device has + * repeating segments. The segment number is the device segment to + * access and the segment descriptor must reference the segment + * being requested. For example the segment number must resided in + * the range [base, base + count). + * + * @param sd The segment descriptor. + * @param device The device to read data from. + * @param segment The segment within the device to read. + * @param offset The offset in the segment to read. + * @param buffer The buffer to read the data into. + * @param size The amount of data to read. + * @retval 0 No error. + * @retval EIO The read did not complete. + */ + int (*read) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment, + uint32_t offset, + void* buffer, + uint32_t size); + + /** + * Write data from the buffer to the device. Return an errno + * error number if the device cannot be written to. A segment + * descriptor can describe more than segment in a device if the + * device has repeating segments. The segment number is the device + * segment to access and the segment descriptor must reference + * the segment being requested. For example the segment number must + * resided in the range [base, base + count). + * + * @param sd The segment descriptor. + * @param device The device to write data from. + * @param segment The segment within the device to write to. + * @param offset The offset in the segment to write. + * @param buffer The buffer to write the data from. + * @param size The amount of data to write. + * @retval 0 No error. + * @retval EIO The write did not complete or verify. + */ + int (*write) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment, + uint32_t offset, + const void* buffer, + uint32_t size); + + /** + * Blank a segment in the device. Return an errno error number + * if the device cannot be read or is not blank. A segment descriptor + * can describe more than segment in a device if the device has + * repeating segments. The segment number is the device segment to + * access and the segment descriptor must reference the segment + * being requested. For example the segment number must resided in + * the range [base, base + count). + * + * @param sd The segment descriptor. + * @param device The device to read data from. + * @param segment The segment within the device to read. + * @param offset The offset in the segment to checl. + * @param size The amount of data to check. + * @retval 0 No error. + * @retval EIO The segment is not blank. + */ + int (*blank) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment, + uint32_t offset, + uint32_t size); + + /** + * Verify data in the buffer to the data in the device. Return an + * errno error number if the device cannot be read. A segment + * descriptor can describe more than segment in a device if the + * device has repeating segments. The segment number is the + * segment to access and the segment descriptor must reference + * the device segment being requested. For example the segment number + * must resided in the range [base, base + count). + * + * @param sd The segment descriptor. + * @param device The device to verify data in. + * @param segment The segment within the device to verify. + * @param offset The offset in the segment to verify. + * @param buffer The buffer to verify the data in the device with. + * @param size The amount of data to verify. + * @retval 0 No error. + * @retval EIO The data did not verify. + */ + int (*verify) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment, + uint32_t offset, + const void* buffer, + uint32_t size); + + /** + * Erase the segment. Return an errno error number if the + * segment cannot be erased. A segment descriptor can describe + * more than segment in a device if the device has repeating + * segments. The segment number is the device segment to access and + * the segment descriptor must reference the segment being requested. + * + * @param sd The segment descriptor. + * @param device The device to erase the segment of. + * @param segment The segment within the device to erase. + * @retval 0 No error. + * @retval EIO The segment was not erased. + */ + int (*erase) (const rtems_fdisk_segment_desc* sd, + uint32_t device, + uint32_t segment); + + /** + * Erase the device. Return an errno error number if the + * segment cannot be erased. A segment descriptor can describe + * more than segment in a device if the device has repeating + * segments. The segment number is the segment to access and + * the segment descriptor must reference the segment being requested. + * + * @param sd The segment descriptor. + * @param device The device to erase. + * @retval 0 No error. + * @retval EIO The device was not erased. + */ + int (*erase_device) (const struct rtems_fdisk_device_desc* dd, + uint32_t device); + +} rtems_fdisk_driver_handlers; + +/** + * @brief Flash Device Descriptor holds the segments in a device. + * + * The placing of the segments in a device decriptor allows the low level + * driver to share the segment descriptors for a number of devices. + * + * Typically this structure is part of a table of segments in the + * device which is referenced in the flash disk configuration table. + * The reference is kept in the driver and used all the time to + * manage the flash device, therefore it must always exist. + */ +typedef struct rtems_fdisk_device_desc +{ + uint32_t segment_count; /**< Number of segments. */ + const rtems_fdisk_segment_desc* segments; /**< Array of segments. */ + const rtems_fdisk_driver_handlers* flash_ops; /**< Device handlers. */ +} rtems_fdisk_device_desc; + +/** + * @brief RTEMS Flash Disk configuration table used to initialise the + * driver. + * + * The unavailable blocks count is the number of blocks less than the + * available number of blocks the file system is given. This means there + * will always be that number of blocks available when the file system + * thinks the disk is full. The compaction code needs blocks to compact + * with so you will never be able to have all the blocks allocated to the + * file system and be able to full the disk. + * + * The compacting segment count is the number of segments that are + * moved into a new segment. A high number will mean more segments with + * low active page counts and high used page counts will be moved into + * avaliable pages how-ever this extends the compaction time due to + * time it takes the erase the pages. There is no pont making this number + * greater than the maximum number of pages in a segment. + * + * The available compacting segment count is the level when compaction occurs + * when writing. If you set this to 0 then compaction will fail because + * there will be no segments to compact into. + * + * The info level can be 0 for off with error, and abort messages allowed. + * Level 1 is warning messages, level 1 is informational messages, and level 3 + * is debugging type prints. The info level can be turned off with a compile + * time directive on the command line to the compiler of: + * + * -DRTEMS_FDISK_TRACE=0 + */ +typedef struct rtems_flashdisk_config +{ + uint32_t block_size; /**< The block size. */ + uint32_t device_count; /**< The number of devices. */ + const rtems_fdisk_device_desc* devices; /**< The device descriptions. */ + uint32_t flags; /**< Set of flags to control + driver. */ + /** + * Number of blocks not available to the file system. This number must be + * greater than or equal to the number of blocks in the largest segment to + * avoid starvation of erased blocks. + */ + uint32_t unavail_blocks; + + uint32_t compact_segs; /**< Max number of segs to + compact in one pass. */ + /** + * The number of segments when compaction occurs when writing. In case the + * number of segments in the available queue is less than or equal to this + * number the compaction process will be triggered. The available queue + * contains all segments with erased blocks. + */ + uint32_t avail_compact_segs; + uint32_t info_level; /**< Default info level. */ +} rtems_flashdisk_config; + +/* + * Driver flags. + */ + +/** + * Leave the erasing of used segment to the background handler. + */ +#define RTEMS_FDISK_BACKGROUND_ERASE (1 << 0) + +/** + * Leave the compacting of of used segment to the background handler. + */ +#define RTEMS_FDISK_BACKGROUND_COMPACT (1 << 1) + +/** + * Check the pages during initialisation to see which pages are + * valid and which are not. This could slow down initialising the + * disk driver. + */ +#define RTEMS_FDISK_CHECK_PAGES (1 << 2) + +/** + * Blank check the flash device before writing to them. This is needed if + * you think you have a driver or device problem. + */ +#define RTEMS_FDISK_BLANK_CHECK_BEFORE_WRITE (1 << 3) + +/** + * Flash disk device driver initialization. Place in a table as the + * initialisation entry and remainder of the entries are the + * RTEMS block device generic handlers. + * + * @param major Flash disk major device number. + * @param minor Minor device number, not applicable. + * @param arg Initialization argument, not applicable. + * @return The rtems_device_driver is actually just + * rtems_status_code. + */ +rtems_device_driver +rtems_fdisk_initialize (rtems_device_major_number major, + rtems_device_minor_number minor, + void* arg); + +/** + * @brief External reference to the configuration. Please supply. + * Support is present in confdefs.h for providing this variable. + */ +extern const rtems_flashdisk_config rtems_flashdisk_configuration[]; + +/** + * @brief External reference to the number of configurations. Please supply. + * Support is present in confdefs.h for providing this variable. + */ +extern uint32_t rtems_flashdisk_configuration_size; + +/** @} */ + +#endif |