Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:13

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSFDisk
0007  *
0008  * @brief Interface to a Flash Disk Block Device
0009  *
0010  * This file defines the interface to a flash disk block device.
0011  */
0012 
0013 /*
0014  * Copyright (C) 2007 Chris Johns
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #if !defined (_RTEMS_FLASHDISK_H_)
0039 #define _RTEMS_FLASHDISK_H_
0040 
0041 #include <stdint.h>
0042 #include <sys/ioctl.h>
0043 
0044 #include <rtems.h>
0045 
0046 #ifdef __cplusplus
0047 extern "C" {
0048 #endif /* __cplusplus */
0049 
0050 /**
0051  * @defgroup RTEMSFDisk Flash Disk Device
0052  *
0053  * @ingroup rtems_blkdev
0054  *
0055  * Flash disk driver for RTEMS provides support for block based
0056  * file systems on flash devices. The driver is not a flash file
0057  * system nor does it try to compete with flash file systems. It
0058  * currently does not journal how-ever block sequence numbering
0059  * could be added to allow recovery of a past positions if
0060  * a power down occurred while being updated.
0061  *
0062  * This flash driver provides block device support for most flash
0063  * devices. The driver has been tested on NOR type devices such
0064  * as the AMLV160 or M28W160. Support for NAND type devices may
0065  * require driver changes to allow speedy recover of the block
0066  * mapping data and to also handle the current use of word programming.
0067  * Currently the page descriptors are stored in the first few pages
0068  * of each segment.
0069  *
0070  * The driver supports devices, segments and pages. You provide
0071  * to the driver the device descriptions as a table of device
0072  * descriptors. Each device descriptor contain a table of
0073  * segment descriptions or segment descriptors. The driver uses
0074  * this information to manage the devices.
0075  *
0076  * A device is made up of segments. These are also called
0077  * sectors or blocks. It is the smallest erasable part of a device.
0078  * A device can have differing size segments at different
0079  * offsets in the device. The segment descriptors support repeating
0080  * segments that are continuous in the device. The driver breaks the
0081  * segments up into pages. The first pages of a segment contain
0082  * the page descriptors. A page descriptor hold the page flags,
0083  * a CRC for the page of data and the block number the page
0084  * holds. The block can appear in any order in the devices. A
0085  * page is active if it hold a current block of data. If the
0086  * used bit is set the page is counted as used. A page moves
0087  * from erased to active to used then back to erased. If a block
0088  * is written that is already in a page, the block is written to
0089  * a new page the old page is flagged as used.
0090  *
0091  * At initialization time each segment's page descriptors are
0092  * read into memory and scanned to determine the active pages,
0093  * the used pages and the bad pages. If a segment has any erased
0094  * pages it is queue on the available queue. If the segment has
0095  * no erased pages it is queue on the used queue.
0096  *
0097  * The available queue is sorted from the least number available
0098  * to the most number of available pages. A segment that has just
0099  * been erased will placed at the end of the queue. A segment that
0100  * has only a few available pages will be used sooner and once
0101  * there are no available pages it is queued on the used queue.
0102  * The used queue hold segments that have no available pages and
0103  * is sorted from the least number of active pages to the most
0104  * number of active pages.
0105  *
0106  * The driver is required to compact segments. Compacting takes
0107  * the segment with the most number of available pages from the
0108  * available queue then takes segments with the least number of
0109  * active pages from the used queue until it has enough pages
0110  * to fill the empty segment. As the active pages are moved
0111  * they flagged as used and once the segment has only used pages
0112  * it is erased.
0113  *
0114  * A flash block driver like this never knows if a page is not
0115  * being used by the file-system. A typical file system is not
0116  * design with the idea of erasing a block on a disk once it is
0117  * not being used. The file-system will normally use a flag
0118  * or a location as a marker to say that part of the disk is
0119  * no longer in use. This means a number of blocks could be
0120  * held in active pages but are no in use by the file system.
0121  * The file system may also read blocks that have never been
0122  * written to disk. This complicates the driver and may make
0123  * the wear, usage and erase patterns harsher than a flash
0124  * file system. The driver may also suffer from problems if
0125  * power is lost.
0126  *
0127  * There are some flash disk specific IO control request types.
0128  * To use open the device and issue the ioctl() call.
0129  *
0130  * @code
0131  *  int fd = open ("/dev/flashdisk0", O_WRONLY, 0);
0132  *  if (fd < 0)
0133  *  {
0134  *    printf ("driver open failed: %s\n", strerror (errno));
0135  *    exit (1);
0136  *  }
0137  *  if (ioctl (fd, RTEMS_FDISK_IOCTL_ERASE_DISK) < 0)
0138  *  {
0139  *    printf ("driver erase failed: %s\n", strerror (errno));
0140  *    exit (1);
0141  *  }
0142  *  close (fd);
0143  * @endcode
0144  */
0145 /**@{**/
0146 
0147 /**
0148  * @brief The base name of the flash disks.
0149  */
0150 #define RTEMS_FLASHDISK_DEVICE_BASE_NAME "/dev/fdd"
0151 
0152 #define RTEMS_FDISK_IOCTL_ERASE_DISK   _IO('B', 128)
0153 #define RTEMS_FDISK_IOCTL_COMPACT      _IO('B', 129)
0154 #define RTEMS_FDISK_IOCTL_ERASE_USED   _IO('B', 130)
0155 #define RTEMS_FDISK_IOCTL_MONITORING   _IO('B', 131)
0156 #define RTEMS_FDISK_IOCTL_INFO_LEVEL   _IO('B', 132)
0157 #define RTEMS_FDISK_IOCTL_PRINT_STATUS _IO('B', 133)
0158 
0159 /**
0160  * @brief Flash Disk Monitoring Data allows a user to obtain
0161  * the current status of the disk.
0162  */
0163 typedef struct rtems_fdisk_monitor_data
0164 {
0165   uint32_t block_size;
0166   uint32_t block_count;
0167   uint32_t unavail_blocks;
0168   uint32_t device_count;
0169   uint32_t segment_count;
0170   uint32_t page_count;
0171   uint32_t blocks_used;
0172   uint32_t segs_available;
0173   uint32_t segs_used;
0174   uint32_t segs_failed;
0175   uint32_t seg_erases;
0176   uint32_t pages_desc;
0177   uint32_t pages_active;
0178   uint32_t pages_used;
0179   uint32_t pages_bad;
0180   uint32_t info_level;
0181 } rtems_fdisk_monitor_data;
0182 
0183 /**
0184  * @brief Flash Segment Descriptor holds, number of continuous segments in the
0185  * device of this type, the base segment number in the device, the address
0186  * offset of the base segment in the device, and the size of segment.
0187  *
0188  * Typically this structure is part of a table of segments in the
0189  * device which is referenced in the flash disk configuration table.
0190  * The reference is kept in the driver and used all the time to
0191  * manage the flash device, therefore it must always exist.
0192  */
0193 typedef struct rtems_fdisk_segment_desc
0194 {
0195   uint16_t count;    /**< Number of segments of this type in a row. */
0196   uint16_t segment;  /**< The base segment number. */
0197   uint32_t offset;   /**< Address offset of base segment in device. */
0198   uint32_t size;     /**< Size of the segment in bytes. */
0199 } rtems_fdisk_segment_desc;
0200 
0201 /**
0202  * @brief Return the number of kilo-bytes.
0203  */
0204 #define RTEMS_FDISK_KBYTES(_k) (UINT32_C(1024) * (_k))
0205 
0206 /**
0207  * Forward declaration of the device descriptor.
0208  */
0209 struct rtems_fdisk_device_desc;
0210 
0211 /**
0212  * @brief Flash Low Level driver handlers.
0213  *
0214  * Typically this structure is part of a table of handlers in the
0215  * device which is referenced in the flash disk configuration table.
0216  * The reference is kept in the driver and used all the time to
0217  * manage the flash device, therefore it must always exist.
0218  */
0219 typedef struct rtems_fdisk_driver_handlers
0220 {
0221   /**
0222    * Read data from the device into the buffer. Return an errno
0223    * error number if the device cannot be read. A segment descriptor
0224    * can describe more than one segment in a device if the device has
0225    * repeating segments. The segment number is the device segment to
0226    * access and the segment descriptor must reference the segment
0227    * being requested. For example the segment number must resided in
0228    * the range [base, base + count).
0229    *
0230    * @param sd The segment descriptor.
0231    * @param device The device to read data from.
0232    * @param segment The segment within the device to read.
0233    * @param offset The offset in the segment to read.
0234    * @param buffer The buffer to read the data into.
0235    * @param size The amount of data to read.
0236    * @retval 0 No error.
0237    * @retval EIO The read did not complete.
0238    */
0239   int (*read) (const rtems_fdisk_segment_desc* sd,
0240                uint32_t                        device,
0241                uint32_t                        segment,
0242                uint32_t                        offset,
0243                void*                           buffer,
0244                uint32_t                        size);
0245 
0246   /**
0247    * Write data from the buffer to the device. Return an errno
0248    * error number if the device cannot be written to. A segment
0249    * descriptor can describe more than segment in a device if the
0250    * device has repeating segments. The segment number is the device
0251    * segment to access and the segment descriptor must reference
0252    * the segment being requested. For example the segment number must
0253    * resided in the range [base, base + count).
0254    *
0255    * @param sd The segment descriptor.
0256    * @param device The device to write data from.
0257    * @param segment The segment within the device to write to.
0258    * @param offset The offset in the segment to write.
0259    * @param buffer The buffer to write the data from.
0260    * @param size The amount of data to write.
0261    * @retval 0 No error.
0262    * @retval EIO The write did not complete or verify.
0263    */
0264   int (*write) (const rtems_fdisk_segment_desc* sd,
0265                 uint32_t                        device,
0266                 uint32_t                        segment,
0267                 uint32_t                        offset,
0268                 const void*                     buffer,
0269                 uint32_t                        size);
0270 
0271   /**
0272    * Blank a segment in the device. Return an errno error number
0273    * if the device cannot be read or is not blank. A segment descriptor
0274    * can describe more than segment in a device if the device has
0275    * repeating segments. The segment number is the device segment to
0276    * access and the segment descriptor must reference the segment
0277    * being requested. For example the segment number must resided in
0278    * the range [base, base + count).
0279    *
0280    * @param sd The segment descriptor.
0281    * @param device The device to read data from.
0282    * @param segment The segment within the device to read.
0283    * @param offset The offset in the segment to checl.
0284    * @param size The amount of data to check.
0285    * @retval 0 No error.
0286    * @retval EIO The segment is not blank.
0287    */
0288   int (*blank) (const rtems_fdisk_segment_desc* sd,
0289                 uint32_t                        device,
0290                 uint32_t                        segment,
0291                 uint32_t                        offset,
0292                 uint32_t                        size);
0293 
0294   /**
0295    * Verify data in the buffer to the data in the device. Return an
0296    * errno error number if the device cannot be read. A segment
0297    * descriptor can describe more than segment in a device if the
0298    * device has repeating segments. The segment number is the
0299    * segment to access and the segment descriptor must reference
0300    * the device segment being requested. For example the segment number
0301    * must resided in the range [base, base + count).
0302    *
0303    * @param sd The segment descriptor.
0304    * @param device The device to verify data in.
0305    * @param segment The segment within the device to verify.
0306    * @param offset The offset in the segment to verify.
0307    * @param buffer The buffer to verify the data in the device with.
0308    * @param size The amount of data to verify.
0309    * @retval 0 No error.
0310    * @retval EIO The data did not verify.
0311    */
0312   int (*verify) (const rtems_fdisk_segment_desc* sd,
0313                  uint32_t                        device,
0314                  uint32_t                        segment,
0315                  uint32_t                        offset,
0316                  const void*                     buffer,
0317                  uint32_t                        size);
0318 
0319   /**
0320    * Erase the segment. Return an errno error number if the
0321    * segment cannot be erased. A segment descriptor can describe
0322    * more than segment in a device if the device has repeating
0323    * segments. The segment number is the device segment to access and
0324    * the segment descriptor must reference the segment being requested.
0325    *
0326    * @param sd The segment descriptor.
0327    * @param device The device to erase the segment of.
0328    * @param segment The segment within the device to erase.
0329    * @retval 0 No error.
0330    * @retval EIO The segment was not erased.
0331    */
0332   int (*erase) (const rtems_fdisk_segment_desc* sd,
0333                 uint32_t                        device,
0334                 uint32_t                        segment);
0335 
0336   /**
0337    * Erase the device. Return an errno error number if the
0338    * segment cannot be erased. A segment descriptor can describe
0339    * more than segment in a device if the device has repeating
0340    * segments. The segment number is the segment to access and
0341    * the segment descriptor must reference the segment being requested.
0342    *
0343    * @param sd The segment descriptor.
0344    * @param device The device to erase.
0345    * @retval 0 No error.
0346    * @retval EIO The device was not erased.
0347    */
0348   int (*erase_device) (const struct rtems_fdisk_device_desc* dd,
0349                        uint32_t                              device);
0350 
0351 } rtems_fdisk_driver_handlers;
0352 
0353 /**
0354  * @brief Flash Device Descriptor holds the segments in a device.
0355  *
0356  * The placing of the segments in a device decriptor allows the low level
0357  * driver to share the segment descriptors for a number of devices.
0358  *
0359  * Typically this structure is part of a table of segments in the
0360  * device which is referenced in the flash disk configuration table.
0361  * The reference is kept in the driver and used all the time to
0362  * manage the flash device, therefore it must always exist.
0363  */
0364 typedef struct rtems_fdisk_device_desc
0365 {
0366   uint32_t                           segment_count; /**< Number of segments. */
0367   const rtems_fdisk_segment_desc*    segments;      /**< Array of segments. */
0368   const rtems_fdisk_driver_handlers* flash_ops;     /**< Device handlers. */
0369 } rtems_fdisk_device_desc;
0370 
0371 /**
0372  * @brief RTEMS Flash Disk configuration table used to initialise the
0373  * driver.
0374  *
0375  * The unavailable blocks count is the number of blocks less than the
0376  * available number of blocks the file system is given. This means there
0377  * will always be that number of blocks available when the file system
0378  * thinks the disk is full. The compaction code needs blocks to compact
0379  * with so you will never be able to have all the blocks allocated to the
0380  * file system and be able to full the disk.
0381  *
0382  * The compacting segment count is the number of segments that are
0383  * moved into a new segment. A high number will mean more segments with
0384  * low active page counts and high used page counts will be moved into
0385  * avaliable pages how-ever this extends the compaction time due to
0386  * time it takes the erase the pages. There is no pont making this number
0387  * greater than the maximum number of pages in a segment.
0388  *
0389  * The available compacting segment count is the level when compaction occurs
0390  * when writing. If you set this to 0 then compaction will fail because
0391  * there will be no segments to compact into.
0392  *
0393  * The info level can be 0 for off with error, and abort messages allowed.
0394  * Level 1 is warning messages, level 1 is informational messages, and level 3
0395  * is debugging type prints. The info level can be turned off with a compile
0396  * time directive on the command line to the compiler of:
0397  *
0398  *     -DRTEMS_FDISK_TRACE=0
0399  */
0400 typedef struct rtems_flashdisk_config
0401 {
0402   uint32_t                       block_size;     /**< The block size. */
0403   uint32_t                       device_count;   /**< The number of devices. */
0404   const rtems_fdisk_device_desc* devices;        /**< The device descriptions. */
0405   uint32_t                       flags;          /**< Set of flags to control
0406                                                       driver. */
0407   /**
0408    * Number of blocks not available to the file system.  This number must be
0409    * greater than or equal to the number of blocks in the largest segment to
0410    * avoid starvation of erased blocks.
0411    */
0412   uint32_t                       unavail_blocks;
0413 
0414   uint32_t                       compact_segs;   /**< Max number of segs to
0415                                                       compact in one pass. */
0416   /**
0417    * The number of segments when compaction occurs when writing.  In case the
0418    * number of segments in the available queue is less than or equal to this
0419    * number the compaction process will be triggered.  The available queue
0420    * contains all segments with erased blocks.
0421    */
0422   uint32_t                       avail_compact_segs;
0423   uint32_t                       info_level;     /**< Default info level. */
0424 } rtems_flashdisk_config;
0425 
0426 /*
0427  * Driver flags.
0428  */
0429 
0430 /**
0431  * Leave the erasing of used segment to the background handler.
0432  */
0433 #define RTEMS_FDISK_BACKGROUND_ERASE (1 << 0)
0434 
0435 /**
0436  * Leave the compacting of of used segment to the background handler.
0437  */
0438 #define RTEMS_FDISK_BACKGROUND_COMPACT (1 << 1)
0439 
0440 /**
0441  * Check the pages during initialisation to see which pages are
0442  * valid and which are not. This could slow down initialising the
0443  * disk driver.
0444  */
0445 #define RTEMS_FDISK_CHECK_PAGES (1 << 2)
0446 
0447 /**
0448  * Blank check the flash device before writing to them. This is needed if
0449  * you think you have a driver or device problem.
0450  */
0451 #define RTEMS_FDISK_BLANK_CHECK_BEFORE_WRITE (1 << 3)
0452 
0453 /**
0454  * Flash disk device driver initialization. Place in a table as the
0455  * initialisation entry and remainder of the entries are the
0456  * RTEMS block device generic handlers.
0457  *
0458  * @param major Flash disk major device number.
0459  * @param minor Minor device number, not applicable.
0460  * @param arg Initialization argument, not applicable.
0461  * @return The rtems_device_driver is actually just
0462  *         rtems_status_code.
0463  */
0464 rtems_device_driver
0465 rtems_fdisk_initialize (rtems_device_major_number major,
0466                         rtems_device_minor_number minor,
0467                         void*                     arg);
0468 
0469 /**
0470  * @brief External reference to the configuration. Please supply.
0471  * Support is present in confdefs.h for providing this variable.
0472  */
0473 extern const rtems_flashdisk_config rtems_flashdisk_configuration[];
0474 
0475 /**
0476  * @brief External reference to the number of configurations. Please supply.
0477  * Support is present in confdefs.h for providing this variable.
0478  */
0479 extern uint32_t rtems_flashdisk_configuration_size;
0480 
0481 /** @} */
0482 
0483 #ifdef __cplusplus
0484 }
0485 #endif /* __cplusplus */
0486 
0487 #endif