Files
m241Neelima/vxworks-6.9/target/h/private/ftl/ftlLibP.h
T
2026-07-30 11:19:44 +05:30

1633 lines
63 KiB
C

/* ftlLibP.h - generic ftl private header */
/*
* Copyright (c) 2012 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
--------------------
01r,18oct13,jxu cleanup of warnings
01q,04sep13,jxu fixed incorrect block version issue.
01p,02sep13,jxu added average age of all data blocks to meta header.
01o,23aug13,jxu supported incremental log.
01n,10jul13,jxu supported clean unmount, and removed group wl info from
map page and added grp_wl_sort, and supported per-device
user configurations.
01m,26jun13,jxu fixed incorrect bits of blkVer in BLOCK_INFO.
01l,25jun13,jxu optimized the alignment for the packed structures.
01k,08jun13,jxu added page status to oob and few flags
01j,05jan13,jxu added debugging tool for tracking lpn mapping and ppn status
01i,07nov12,jxu added memory statistics for ftl
01h,06nov12,jxu added support of ftl discard feature.
01g,08nov12,jxu added more info to ftl identity and added wl info to meta log.
01f,22oct12,jxu added pFpioReqBmp to support doing mapping for multiple
non-contiguous page read.
01e,09jul12,jxu adapted for integration.
01d,18jun12,m_y added wl related defines.
01c,17may12,x_z added bm related defines.
01b,15may12,jxu revised based on internal review.
01a,29feb12,jxu written.
*/
#ifndef __INCftlLibPh
#define __INCftlLibPh
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* includes */
/*
* change following includes when the header files are moved to the
* standard header file location
*/
#include <flash.h>
#include <ftlLib.h>
#include <private/ftl/ftlOsIf.h>
#include <private/ftl/ftlUtilP.h>
/* defines */
#define FTL_DIAGNOSTIC /* for diagnostic purpose */
#define FTL_CLEAN_UNMOUNT /* clean unmount and re-format */
#define FTL_CHECKSUM_META /* additional checksum for meta data */
/* user configuration bit position */
#define FTL_CACHE_ON 0x1
#define FTL_TASK_ON 0x2
#define FTL_DISCARD_ON 0x4
#define INIT_USER_CONFIG(pFtl) (((pFtl)->usrConfig = 0))
#define ENABLE_CACHE(pFtl) (((pFtl)->usrConfig |= FTL_CACHE_ON))
#define ENABLE_DISCARD(pFtl) (((pFtl)->usrConfig |= FTL_DISCARD_ON))
#define ENABLE_TASK(pFtl) (((pFtl)->usrConfig |= FTL_TASK_ON))
#define IS_CACHE_ENABLED(pFtl) (((pFtl)->usrConfig & FTL_CACHE_ON) != 0)
#define IS_DISCARD_ENABLED(pFtl) (((pFtl)->usrConfig & FTL_DISCARD_ON) != 0)
#define IS_TASK_ENABLED(pFtl) (((pFtl)->usrConfig & FTL_TASK_ON) != 0)
/*
* As for some arch like ARM, packing the necessary individual fields of a
* structure is better for the compiler to optimize for performance.
* It's also a good practice to defined the fields as self-aligned.
* Accessing unaligned fields will need execute more memory load/store
* instructions than aligned access.
*/
#define _FTL_PACKED __attribute__((packed))
#define _FTL_PACK_ALIGN(bytes) _WRS_PACK_ALIGN(bytes)
/* FTL PIO error defines */
#define FTL_OK OK
#define FTL_ERROR ERROR /* -1 */
#define FTL_ERR_BLANK (FTL_ERROR - 1)
#define FTL_BM_ERR_ECC_RECV (FTL_ERROR - 2)
#define FTL_BM_ERR_ECC_UNRECV (FTL_ERROR - 3)
#define FTL_BM_ERR_ECC_UNRECV_FAKE (FTL_ERROR - 4)
#define FTL_BM_ERR_WRITE_FAIL (FTL_ERROR - 5)
#define FTL_BM_ERR_ERASE_FAIL (FTL_ERROR - 6)
#define FTL_BM_ERR_DEV_FAIL (FTL_ERROR - 7)
#define FTL_VER_1_0 0x0100
#define FTL_VER FTL_VER_1_0
#define FTL_MAGIC 0x5ACF /* 'W' 'R' 'F' 'T' 'L' */
#define FTL_MODE_RDONLY 0x1
#define FTL_MODE_RW 0x2
#define FTL_UNMOUNT_REFCNT 0x100000
#define FTL_OOB_VER 0
#define FTL_FLAG_MNT_ERR_LOG 0x1
#define FTL_FLAG_MNT_ERR_MAP 0x2
#define FTL_FLAG_CHKSUM_META 0x4
#define META_FLAG_CHKSUM 0x1
/* the first two blocks for saving ftl identify */
#define FTL_NUM_ID_BLKS 2
#define FTL_INVALID_LBN UINT_MAX /* maximum of fblock_t */
#define FTL_LBN_ANY UINT_MAX /* maximum of fblock_t */
#define FTL_INVALID_LPN USHRT_MAX /* maximum of fpage_t*/
#define FTL_INVALID_PBN FTL_INVALID_LBN
#define FTL_INVALID_PPN FTL_INVALID_LPN
#define FTL_INVALID_GRP USHRT_MAX /* maximum of UINT16 */
#define FTL_INVALID_AGE UINT_MAX /* maximum of blk_age_t */
#define INVALID_BLKINFO {FTL_INVALID_PBN, 0, 0}
#define INVALID_ADDR {FTL_INVALID_PBN, FTL_INVALID_PPN, 0}
#define ASSIGN_ADDR(pDestAddr, blkno, pageno, off) { \
((FTL_ADDR *)(pDestAddr))->blkNo = blkno; \
((FTL_ADDR *)(pDestAddr))->pageNo = pageno; \
((FTL_ADDR *)(pDestAddr))->offset = off; \
}
#define COPY_ADDR(destAddr, srcAddr) { \
((FTL_ADDR *)(destAddr))->blkNo = ((FTL_ADDR *)(srcAddr))->blkNo; \
((FTL_ADDR *)(destAddr))->pageNo = ((FTL_ADDR *)(srcAddr))->pageNo; \
((FTL_ADDR *)(destAddr))->offset = ((FTL_ADDR *)(srcAddr))->offset; \
}
/* ftl block types */
#define FTL_BLK_TYPE_BLANK 0x0
#define FTL_BLK_TYPE_META 0x1
#define FTL_BLK_TYPE_DATA 0x2
#define FTL_BLK_TYPE_ASSOC 0x3
#define FTL_BLK_TYPE_REPL 0x4
#define FTL_NUM_ASSOC_BLK_LIST 4 /* # of used associate block lists */
/*
* # of house keeping blocks for operations that could release
* more blocks.
*/
#define FTL_NUM_HSKP_BLOCK 1
#define FTL_FLAG_CHECK_FACTORY_BLK 0x1
#define FTL_BLANK_PATTERN ((char)0xFF)
/*
* maximum number of associate block for one logical block, it's
* configurable and currently it is defined as one. Its up limit
* is 8.
*/
#define FTL_CFG_MAX_ASSOC_BLKS_PER_LBN 4 /* maximum configurable # */
#define FTL_MAX_ASSOC_BLKS_PER_LBN 1 /* current # */
#define FTL_DEV_NAME_LEN_MAX 64 /* FTL device name */
#define FTL_EMPTY_PATTERN 0 /* pattern for filling blank page */
/* flash I/O flags */
#define FIO_READ 0x1 /* read operation */
#define FIO_WRITE 0x2 /* write operation */
#define FIO_DATA 0x4 /* access data area of nand page */
#define FIO_OOB 0x8 /* access oob area of nand page */
#define FIO_SG 0x10 /* scatter-gather I/O */
#define FIO_INCACHE 0x20 /* in cache */
#define FIO_SYNC 0x40 /* synchronously I/O */
#define FIO_EXCL 0x80 /* involved in exclusive operation */
#define FIO_BUSY 0x100 /* in busy */
#define FIO_DONE 0x200 /* completed */
#define FIO_ERROR 0x400 /* error */
#define FIO_DISCARD 0x1000 /* discarded fpio */
#define FIO_NO_MAPPING 0x2000 /* do not need mapping */
#define FIO_STOP_BLANK 0x4000 /* stop when meet blank page */
#define FIO_STOP_ERROR 0x8000 /* stop when meet error page */
#define FIO_STOP_OK 0x10000 /* stop when meet a good page */
#define FIO_WRITE_VERIFY 0x20000 /* verify data after write */
#define FIO_BUF_DMA 0x40000 /* DMA buffer */
#define FIO_CHECK_BLANK 0x80000 /* check blank page */
#define FIO_CHECK_FILLED_BLANK 0x100000 /* check filled blank page */
#define FIO_BYPASS_BBMT 0x200000 /* bypass checking bbmt */
#define FIO_BYPASS_BBM_ERR_HDL 0x400000 /* bypass bbm error handling */
#define FIO_COPY_FULL_PAGE 0x800000 /* copy full page */
#define FIO_RAW_DATA 0x1000000 /* read or write data without ecc */
#define FIO_WR_ERR_PAGE 0x2000000 /* write error page */
#define FIO_USER_DATA 0x4000000 /* read or write user data */
#define FIO_META_DATA 0x8000000 /* read or write meta data */
#define FIO_COPY_UPDATE_OOB 0x10000000 /* should update oob when copying */
#define FIO_TEST_BLANK_BITS 0x80000000 /* TEMP for testing */
/* lbn control flags */
/* #define LBN_FLAG_READ 0x1 */
/* #define LBN_FLAG_WRITE 0x2 */
#define LBN_FLAG_NO_WAIT 0x4
#define LBN_FLAG_EXCL 0x8
/* ftl ioctl commands */
#define FTL_IOC_DISCARD 0x1 /* discard command */
#define FTL_IOC_FLUSH 0x2 /* flush command */
#define FLUSH_OPT_NONE 0x0 /* no additional option */
#define FLUSH_OPT_ONE_BLK 0x1 /* flush one block */
#define FLUSH_OPT_RECLAIM_FBIO 0x2 /* reclaim fbio instance for use */
#define FTL_EMBED_FPIOS 1 /* how many fpios are embedded in a */
/* fbio */
#define FTL_WL_OPT_ONCE 0x1
#define FTL_AGE_MAX UINT_MAX
#ifdef FTL_DEBUG
#define FTL_AGE_THRESH_DELTA 100
#else
#define FTL_AGE_THRESH_DELTA 100
#endif /* FTL_DEBUG */
#define FTL_WL_LAZY_MODE_ENABLED FALSE
/* meta data type */
#define FTL_META_TYPE_LOG 0x5A
#define FTL_META_TYPE_MAP 0xAC
#define FTL_SIZE_META_LOG(pFtl) (pFtl->pBm->pageSize)
#define META_HEADER_SIZE (ROUND_UP (sizeof (FTL_META_HEADER), 4))
#define MAP_FLAG_INVALID 0x1 /* invalid block map */
#define MAP_FLAG_DIRTY 0x2 /* dirty block map */
/* flags for associate blocks management */
#define FTL_ASSOC_FLAG_READ 0x1 /* read */
#define FTL_ASSOC_FLAG_WRITE 0x2 /* write */
#define FTL_ASSOC_FLAG_RANDOM 0x4 /* random I/O */
#define FTL_ASSOC_FLAG_SEQ 0x8 /* sequential I/O */
#define FTL_ASSOC_FLAG_FULL 0x10 /* sequential I/O */
#define FTL_ASSOC_FLAG_USED 0x100 /* used */
#define FTL_ASSOC_FLAG_GC 0x200 /* allow GC */
#define FTL_ASSOC_FLAG_ALLOC 0x400 /* dynamically allocated */
#define FTL_ASSOC_FLAG_INVALID 0x800 /* invalid page mapping in RAM */
#define FTL_ASSOC_FLAG_HSKP 0x1000 /* house-keeping associate blocks */
#define FTL_ASSOC_FLAG_IN_TREE 0x2000 /* in tree */
#define IS_ASSOC_BLK_HSKP(pAssocBlk) \
IS_FLAG_SET((pAssocBlk)->flags, FTL_ASSOC_FLAG_HSKP)
/* flags for background service task */
#define FTL_SVC_REQ_WL 0x1
#define FTL_SVC_REQ_GC 0x2
#define FTL_SVC_REQ_DISCARD 0x4
#define FTL_SVC_REQ_FLUSH 0x8
#define DISCARD_FLAG_ONE_BLK 0x1 /* discard one block */
/* macros help check the status of a fbio */
#define IS_FBIO_FREE(pFbio) ( \
(DLL_EMPTY (&(pFbio)->cleanFpioList)) && \
(DLL_EMPTY (&(pFbio)->dirtyFpioList)) \
)
#define IS_FBIO_CLEAN(pFbio) ( \
(!DLL_EMPTY (&(pFbio)->cleanFpioList)) && \
(DLL_EMPTY (&(pFbio)->dirtyFpioList)) \
)
#define IS_FBIO_DIRTY(pFbio) ( \
!DLL_EMPTY (&(pFbio)->dirtyFpioList) \
)
/* macros help get the container structure through a member of it */
#define CONTAINER_OF(ptr, type, member) \
((type*)((char *)(ptr) - OFFSET(type,member)))
#define DL_NODE_TO_BM_DESC(pNode) ((FTL_BM_DESC *)(pNode))
#define DL_NODE_TO_LBN_CTRL(node) \
CONTAINER_OF((node), struct lbn_ctrl_entry, listNode)
#define NODE_TO_FBIO(node) \
CONTAINER_OF((node), struct ftl_bio, listNode)
#define NODE_TO_FPIO(node) \
CONTAINER_OF((node), struct ftl_pio, fpioNode)
#define NODE_TO_MP_BUF(pNode) \
CONTAINER_OF(pNode, struct mp_buf_info, node)
#define NODE_TO_PG_MAP(pNode) \
CONTAINER_OF(pNode, struct lbn_pg_map, listNode)
#define DL_NODE_TO_ASSOC_BLK(pNode) \
CONTAINER_OF(pNode, struct assoc_blk_entry, listNode)
#define AVL_NODE_TO_ASSOC_BLK(pNode) \
CONTAINER_OF(pNode, struct assoc_blk_entry, avlNode)
#define AVL_NODE_TO_DISCARD_NODE(pNode) \
CONTAINER_OF(pNode, struct ftl_discard_node, avlNode)
#define DL_NODE_TO_DISCARD_NODE(pNode) \
CONTAINER_OF(pNode, struct ftl_discard_node, listNode)
#define ASSOC_HEAD(pPgMap) ((pPgMap)->pAssocBlks)
#define ASSOC_TAIL(pNode, pHead) do { \
for (pNode = pHead; pNode->pNext != NULL; pNode = pNode->pNext); \
}while(0)
#define ASSOC_NEXT(pNode) ((pNode)->pNext)
#define ASSOC_FOREACH(pNode, pHead) \
for (((pNode) = (pHead)); \
((pNode) != NULL); \
((pNode) = (pNode)->pNext))
/*
* block version convention:
* 1. Version is composed of major and minor version.
* 2. The block which has lower major version is data block, otherwise
* it is associate block.
* 3. For blocks which have equal major version, the block with higher
* minor version contains newer data.
*/
#define BLK_VER_MASK ((0x1 << 6) - 1)
#define MAJOR_VER_MAX 0x7
#define MINOR_VER_MAX 0x7
#define MAJOR_VER_MASK 0x7
#define MINOR_VER_MASK 0x7
#define MINOR_VER_SHIFT 0 /* low 3 bits for minor version */
#define MAJOR_VER_SHIFT 3 /* high 3 bits for major version */
#define MAJOR_VER(ver) (((ver) >> MAJOR_VER_SHIFT) & MAJOR_VER_MASK)
#define MINOR_VER(ver) (((ver) >> MINOR_VER_SHIFT) & MINOR_VER_MASK)
#define MAJOR_VER_SET(ver, value) ((ver) = ((((value) << MAJOR_VER_SHIFT) | \
(MINOR_VER(ver) << MINOR_VER_SHIFT)) & BLK_VER_MASK))
#define MINOR_VER_SET(ver, value) ((ver) = ((((value) << MINOR_VER_SHIFT) | \
(MAJOR_VER(ver) << MAJOR_VER_SHIFT)) & BLK_VER_MASK))
#define MAJOR_VER_INC(ver) \
MAJOR_VER_SET(ver, ((MAJOR_VER (ver) + 1) & MAJOR_VER_MASK));
#define MINOR_VER_INC(ver) \
MINOR_VER_SET(ver, ((MINOR_VER (ver) + 1) & MINOR_VER_MASK));
#define MAJOR_VER_DEC(ver) \
MAJOR_VER_SET(ver, ((MAJOR_VER (ver) - 1) & MAJOR_VER_MASK));
/* for use by recovering */
#define MAJOR_VER_COMPARE(ver1, ver2) \
blkVerCompare(ver1, ver2, TRUE)
#define MINOR_VER_COMPARE(ver1, ver2) \
blkVerCompare(ver1, ver2, FALSE)
#define OOB_BLK_VER(pOob) (pOob->blkVer & BLK_VER_MASK)
/* maximum blocks to be written by a single fpio */
#define FPIO_MAX_WR_BLKS 3 /* a data block and two associate */
/* block */
#ifdef FTL_DEBUG
#define FTL_DBG_FLAG_REBOOT_HINT 0x1
#endif /* FTL_DEBUG */
/* typedefs */
/* ftl memory budget */
typedef enum mem_budget_t
{
MEM_BDGT_TIGHT = 0,
MEM_BDGT_MODEST,
MEM_BDGT_ABUNDANT
}MEM_BUDGET_T;
/* ftl oob type */
typedef enum flt_oob_type
{
FTL_OOB_TYPE_LARGE = 1,
FTL_OOB_TYPE_SMALL
}FTL_OOB_TYPE;
/* flash specific type definitions */
typedef UINT64 faddr_t; /* general size type */
typedef UINT32 fblock_t; /* block address type */
typedef UINT16 fpage_t;/* page address in block */
typedef UINT32 fbsize_t; /* block size type */
typedef UINT16 fpsize_t;/* page size type */
typedef UINT32 blk_age_t; /* type of age of block */
typedef long FTL_IOCTL_ARG_T;/* ftl ioctl third argument type */
/* flash block I/O completion function type */
struct ftl_bio; /* forward declaration */
struct ftl_desc; /* forward declaration */
typedef void (*FTL_BIO_DONE_FUNC)(struct ftl_bio *);
typedef int (*FTL_BLKDEV_CREATE_FUNC) (struct ftl_desc * pFtlDesc);
typedef int (*FTL_BLKDEV_DELETE_FUNC) (void * pBlkDev);
/* index of each sub-section of a log page */
typedef enum log_index
{
/*
* Each item in this enumeration is defined as an index for a
* sub-section of a mapping page.
*/
LOG_IDX_EVENT = 0, /* event */
LOG_IDX_MP, /* map page address table */
LOG_IDX_ASSOC_BLK, /* associate blocks */
LOG_IDX_ASSOC_AGE, /* age of associate blocks */
LOG_IDX_MAX /* maximum number of sections of mapping page */
}LOG_INDEX;
typedef enum mp_index
{
/*
* Each item in this enumeration is defined as an index for a
* sub-section of a mapping page.
*/
MP_IDX_MAP = 0, /* mapping info */
MP_IDX_BLK_INFO, /* block info */
MP_IDX_MAX /* maximum number of sections of mapping page */
}MP_INDEX;
/* ftl device status */
typedef enum ftl_status
{
FTL_STATUS_INVALID = 0,
FTL_STATUS_FORMAT, /* in formatting */
FTL_STATUS_MOUNT, /* in mounting */
FTL_STATUS_UNMOUNT, /* is being unmounted */
FTL_STATUS_READY, /* ftl device ready */
FTL_STATUS_RDONLY, /* ftl device is read only */
FTL_STATUS_PANIC, /* ftl panic happened */
FTL_STATUS_RECOVER /* in recovering */
}FTL_STATUS;
/* flash address type */
typedef struct ftl_addr_t
{
/*
* Defining a uniform flash address type in a structure is more
* flexible for future modification and evolvement.
*/
fblock_t blkNo; /* global block number */
fpage_t pageNo; /* page number in block */
/*
* The offset is supposed to be 0, which denotes the starting position
* of a flash page, if the block layer uses the page size as its own
* block size. However, there might be user of FTL which uses
* fixed block size (e.g. 512 bytes) that is less than the flash page
* size. To satisfy this kind of users, FTL has to support small block
* emulation. As described in FTL-REQ-6 of the HLD, Wind River FTL will
* support block emulation scaling from 512 byte to native page size
* (e.g. 4KB) of SLC chips (in 1st phase) and other flash types (in
* 2nd phase).
*/
fpsize_t offset; /* offset in page */
}FTL_ADDR;
/* flash page aligned address type */
typedef struct ftl_addr_al_t
{
fblock_t blkNo; /* global block number */
fpage_t pageNo; /* page number in block */
}_FTL_PACK_ALIGN(2) FTL_ADDR_AL;
typedef struct ftl_lbn_ctrl_pool /* lbn control pool */
{
FTL_LOCK_T lbnTrLock; /* lbn control tree access lock */
AVL_TREE lbnTree; /* lbn control tree */
int lbnCnt; /* current # of lbn controls */
int maxResLbnCtrls; /* maximum # of resident lbn controls */
DL_LIST freeLbnCtrlList; /* free fbio list */
FTL_SEM_T semCntFreeLbnCtrl; /* count semphore tracking free fbios */
}FTL_LBN_CTRL_POOL;
typedef struct fbio_pool /* fbio pool */
{
FTL_LOCK_T lock; /* lbn control tree access lock */
int fbioCnt; /* current # of lbn controls */
int maxResFbios; /* maximum # of resident lbn controls */
DL_LIST freeFbioList; /* free fbio list */
FTL_SEM_T semCntFreeFbio; /* count semphore tracking free fbios */
}FBIO_POOL;
/* logical block access control */
typedef struct lbn_ctrl_entry
{
AVL_NODE avlNode; /* AVL tree node, must be first */
fblock_t lbn; /* logical block number, as key */
FTL_LOCK_RW_T lbnRwLock; /* read/write lock */
FTL_ATOMIC32_T refCnt; /* reference count */
DL_NODE listNode; /* free list node */
}LBN_CTRL_ENTRY;
/* page mapping entry of associate blocks */
typedef struct assoc_pme
{
/*
* This structure is for locating the physical page in a associate
* block for a page number of a logical block.
*/
fblock_t assocPbn; /* pbn of associate block */
fpage_t ppn; /* page number in a associate block */
}ASSOC_PME;
typedef struct map_blk_info /* block info of a physical block */
{
fblock_t blkNo; /* block number */
UINT8 blkVer; /* block version */
UINT32 blkAge; /* block age */
}MAP_BLK_INFO;
typedef struct fpio_map_info /* fpio mapping private info */
{
FTL_ADDR physAddr; /* physical address */
ASSOC_PME * pPmeTbl; /* associate page mapping */
void * pBlkInfo; /* physical block info for this fpio */
/*
* Following is a convention to use the mapping information
* contained in this structure.
*
* if (pPmeTbl is NULL) {
* use physAddr directly.
* if (pFpio->fpioLen > pageSize) {
* physAddr implies multiple consecutive physical addresses.
* }
* } else {
* use the pPmeTbl to get the physical address for each page.
* }
*/
}FPIO_MAP_INFO;
/* flash page I/O */
typedef struct ftl_pio
{
DL_NODE fpioNode; /* node of pioList of ftl_bio */
/*
* As an optimization, multiple page I/O requests might be
* combined into one if their I/O address are consecutive
* as well as their buffers. This optimization is only applied
* to the case without cache. In the case of cache enabled,
* the fpioLen is always equal to the size of one page.
*/
FTL_ADDR fromAddr; /* starting flash I/O address */
size_t dataLen; /* length of data */
fpage_t nPages; /* will be figured out by LBD */
char * pBuf; /* data buffer */
char * pOobBuf; /* oob buffer */
FPIO_MAP_INFO mapInfo; /* mapping private information */
int flags; /* FPIO_DIRTY, FPIO_CLEAN, FPIO_READ, */
/* FPIO_WRITE, FPIO_BUSY, FPIO_DONE, */
/* FPIO_DISCARD, FPIO_ERROR */
int error; /* error status of the operation */
FTL_ADDR errAddr; /* which page caused I/O failure */
void * owner; /* owner of this pio, not used */
}FTL_PIO;
/* flash block I/O */
typedef struct ftl_bio
{
DL_NODE listNode; /* node of fbio list */
LBN_CTRL_ENTRY * pLbnCtrl; /* under which lbn control */
/*
* Since the main mapping method of this FTL is block oriented, it
* would be better to support I/O operations on a block basis in
* terms of performance because it saves cost of translation.
*/
fblock_t lbn; /* logical block number */
DL_LIST fpioList; /* requested page I/O list */
DL_LIST * pReqFpioList; /* pointer to the fpio list */
int fbioFlags; /* FBIO_READ, FBIO_WRITE, FBIO_CACHE, */
/* FBIO_DISCARD, FBIO_EXCL, ... */
int error; /* error status of the operation */
FTL_BIO_DONE_FUNC fbioDone; /* Completion function of block I/O */
/*
* embedded a number of fpios in fbio to avoid dynamically
* allocating memory too frequently. It's only useful in
* the case of cache bypassed or disabled.
*/
struct ftl_pio fpios[FTL_EMBED_FPIOS]; /* embedded fpios */
/*
* cache-specific info. If cache module is disabled, following stuff
* is meaningless. However, to simplify things, we don't pack them
* into a seperate strcutrue.
*/
FTL_ATOMIC32_T hitCnt; /* counter of cache hit */
/*
* We purge the dirty data in cache in block granularity.
* The dirty blocks are linked in a LRU (least recently used)
* fashion. When purging a dirty block, all of its dirty pages
* will be written to the underlying flash device synchronously.
*/
DL_LIST dirtyFpioList; /* dirty page I/O list */
DL_LIST cleanFpioList; /* clean page I/O list */
/*
* We use a bitmap to track the cached fpios in above lists. With
* the bitmap, we can determine which pages are cached and what
* are not without searching the list each time we want to know
* that.
*/
UINT8 * pFpioBmp; /* bitmap of fpios */
UINT8 * pFpioReqBmp; /* bitmap of requested fpios */
int bmpLen; /* length of fpio bit map in bytes */
}FTL_BIO;
/* ftl discard support */
typedef struct ftl_discard_info /* ftl discard information */
{
faddr_t startAddr; /* starting address */
size_t length; /* length in bytes */
}FTL_DISCARD_INFO;
typedef struct ftl_blk_discard_info /* ftl block discard information */
{
fblock_t blkAddr; /* block number */
fbsize_t blkOff; /* offset in block */
fbsize_t length; /* length in bytes */
void * pMpInfo; /* mapping private info */
}FTL_BLK_DISCARD_INFO;
typedef struct ftl_discard_node /* ftl block discard node */
{
AVL_NODE avlNode; /* node in the tree */
fblock_t lbn; /* block number */
void * pDiscardBmp; /* bitmap tracking discarded pages */
UINT16 nDiscardedPages;
UINT16 flags; /* flags for the node */
DL_NODE listNode; /* node for fully/partially discarded block */
FTL_TICK_T birthTime; /* when the node came to live */
}FTL_DISCARD_NODE;
typedef struct ftl_discard /* ftl discard support */
{
FTL_LOCK_T discardLock; /* discard lock */
int curCnt; /* current # of discard nodes */
int maxResCnt; /* maximum # of resident discard */
/* nodes */
int discardBmpLen; /* bmp length of discarded pages in */
/* a block */
AVL_TREE discardTree; /* discard tree */
FTL_LOCK_T discardListLock; /* discarded block list lock */
DL_LIST discardList; /* discard block list */
FTL_TICK_T birthTime; /* when it comes to live */
}FTL_DISCARD;
typedef struct ftl_mark_t
{
/*
* ftl erased block or written pages should always contains following
* mark
*/
UINT8 ftlMark; /* one byte is enough to mark if the block */
/* is touched by ftl or not */
}_FTL_PACK_ALIGN(1) FTL_MARK_T;
/* ftl managed oob data, 9 bytes in total, suitable for <= 16bytes size oob */
typedef struct ftl_oob_small
{
UINT32 oobVer : 2; /* OOB version for future evolvement */
UINT32 blkVer : 6; /* block version */
UINT32 lbn : 24; /* logic block number */
UINT32 lpn : 10; /* logic page number */
UINT32 age : 18; /* age of block */
UINT32 blank : 1; /* blank page */
UINT32 error : 1; /* ecc unrecoverable error page */
UINT32 resv : 2; /* reserved */
UINT8 crc8; /* checksum of oob */
}_FTL_PACK_ALIGN(1) FTL_OOB_SMALL;
#define SMALL_OOB_INVALID_LBN (FTL_INVALID_LBN & 0xFFFFFF) /* 24bits */
#define SMALL_OOB_INVALID_LPN (FTL_INVALID_LPN & 0x3FF) /* 10bits */
#define SMALL_OOB_INVALID_AGE (FTL_INVALID_AGE & 0x3FFFF) /* 18bits */
#define SMALL_OOB_LBN(pOob) \
((pOob)->lbn == SMALL_OOB_INVALID_LBN ? FTL_INVALID_LBN : (pOob)->lbn)
#define SMALL_OOB_LPN(pOob) \
((pOob)->lpn == SMALL_OOB_INVALID_LPN ? FTL_INVALID_LPN : (pOob)->lpn)
#define SMALL_OOB_AGE(pOob) \
((pOob)->age == SMALL_OOB_INVALID_AGE ? FTL_INVALID_AGE : (pOob)->age)
/* ftl managed OOB data, 16 bytes in total, suitable for >= 16bytes size OOB */
typedef struct ftl_oob_large
{
UINT8 oobVer : 2; /* OOB version for future evolvement */
UINT8 blkVer : 6; /* block version */
UINT8 blank : 1; /* blank page */
UINT8 error : 1; /* ecc unrecoverable error page */
UINT8 resv1 : 6; /* reserved */
UINT8 resv2[2]; /* reserved */
UINT32 lbn; /* logic block number */
UINT16 lpn; /* logic page number in block */
UINT32 age; /* age of block */
UINT8 resv3; /* reserved */
UINT8 crc8; /* checksum of oob */
}_FTL_PACK_ALIGN(1) FTL_OOB_LARGE;
typedef struct ftl_oob_ram /* ftl oob in ram */
{
UINT8 oobVer; /* OOB version for future evolvement */
UINT8 blkVer; /* block version */
fblock_t lbn; /* logic block number */
fpage_t lpn; /* logic page number in block */
blk_age_t age; /* age of block */
BOOL blank; /* blank page */
BOOL error; /* error page */
}FTL_OOB_RAM;
/* meta page header */
typedef struct ftl_meta_header
{
/* All meta pages are started with this header. */
UINT32 magic; /* magic number to identify a valid */
/* meta page */
UINT8 flags; /* set to 0 if no flags */
UINT8 type; /* meta data or log */
UINT16 grpNo; /* group number */
UINT64 seqNo; /* sequence number, useless */
UINT32 ageAvg; /* average age of all data blocks */
UINT32 privBlk; /* privious block */
UINT8 reserved[4]; /* reserved */
UINT32 dataLen; /* data length of a map page */
UINT32 dataChksum; /* checksum of data part */
UINT32 hdrChksum; /* checksum of header and data */
}_FTL_PACK_ALIGN(4) FTL_META_HEADER; /* 40 bytes in total */
typedef enum merge_t /* merge type */
{
MERGE_INIT = 0,
MERGE_FULL,
MERGE_COPY,
MERGE_SWITCH,
MERGE_DISCARD,
}MERGE_T;
typedef enum log_event
{
LOG_EVENT_INIT = 0x11,
LOG_EVENT_GC = 0x22,
LOG_EVENT_WL = 0x33,
LOG_EVENT_DISCARD = 0x44,
LOG_EVENT_RECOVER = 0x55
}LOG_EVENT;
typedef struct ftl_meta_log /* ftl meta log */
{
/* info for the GC & WL operation that should be logged */
UINT8 event; /* what event is this log for */
UINT8 subEvent; /* the more specific event */
UINT16 pad; /* reserved */
UINT32 lbn; /* on which lbn the event happens */
UINT32 dataPbn; /* pbn for the lbn */
UINT32 dataBlkAge; /* age of the pbn */
UINT32 assocIdx; /* index of the assoc blk involved */
UINT32 assocPbn; /* pbn of the assoc blk involved */
UINT32 nOldAssocBlks; /* # of additional involved assoc blk */
UINT32 oldAssocBlks[FTL_CFG_MAX_ASSOC_BLKS_PER_LBN];
/* the last mp update address, saved for being checked by the next mount */
UINT32 mpBlkNo;
UINT32 mpPageNo;
#ifdef obsolete
FTL_ADDR_AL mpUpdateAddr; /* map page address for the update */
#endif
/* wl info */
UINT32 ageAvg; /* average age */
UINT32 wlAgeThresh; /* weal-leveling threshold */
UINT64 ageSum; /* current total age of all blocks */
UINT8 reserved[4]; /* reserved */
}_WRS_PACK_ALIGN(4) FTL_META_LOG; /* 60 bytes in total */
typedef struct grp_wl_info /* wl info for each group */
{
UINT32 youngestBlk; /* youngest block index */
UINT32 youngestAge; /* age of the block */
UINT32 ageSum; /* total age of this group */
}GRP_WL_INFO;
typedef struct grp_wl_sort
{
fblock_t * pBlks; /* blocks of the group */
blk_age_t * pBlkAge; /* age of each blocks */
int startIdx; /* where to start sorting */
int endIdx; /* when to stop sorting */
/* youngest block in the current range of blocks */
fblock_t youngBlk;
blk_age_t youngAge;
}GRP_WL_SORT;
typedef struct meta_log_buf_info /* meta log buf info in RAM */
{
char * pBuf; /* the address of raw buffer */
FTL_META_HEADER * pLogHeader; /* pointer to the log header */
FTL_META_LOG * pMetaLog; /* pointer to the meta log */
FTL_ADDR_AL * pGrpMpAddr; /* pointer to the grp/mp table */
UINT32 * pAssocBlks; /* pointer to the associate blocks */
UINT32 * pAssocAge; /* pointer to the associate block age */
}META_LOG_BUF_INFO;
/* meta page layout entry */
typedef struct meta_layout
{
UINT32 offset; /* offset of a section */
/* UINT16 length; */ /* length of a section, not necessary */
}META_LAYOUT;
typedef struct block_info /* block info saved with block map */
{
UINT32 blkVer : 6; /* both major and minor block version */
UINT32 resv : 2; /* reserved */
UINT32 age : 24; /* block age */
}_FTL_PACK_ALIGN(1) BLOCK_INFO;
/* pointers to mapping page buffer */
typedef struct mp_buf_info
{
DL_NODE node; /* node in a used or free list */
DL_NODE hashNode; /* node in hash list */
UINT16 grpNo; /* group number */
UINT16 nDataBlks; /* # of data blocks in this group */
int flags;
/*
* This structure contains various pointers which point to each
* sub-sections of a mapping page that are loaded in RAM. They
* should be filled based on the layout of a mapping page (see
* struct mp_layout).
*/
FTL_META_HEADER * pHeader; /* pointer to meta page header */
fblock_t * pBlkMap; /* pointer to mapping array which is
* indexed with LBN */
BLOCK_INFO * pBlkInfo; /* age, version, etc */
}MP_BUF_INFO;
/* address of meta pages for a group */
typedef struct grp_mp_info
{
/*
* This structure contains the address of the valid mapping and age
* pages for a group. Each group should have a entry of this structure
* type.
*/
FTL_ADDR_AL * pMpAddr; /* valid physical address of map page */
MP_BUF_INFO * pMpBuf; /* It's NULL if not loaded */
}GRP_MP_INFO;
/* associate block list entry */
typedef struct assoc_blk_entry
{
/*
* This structure is for managing associate blocks. Each associate
* block has a entry of this type to track the next free page
* number of the associate block and to which logical block is this
* associate block is assigned.
*/
fblock_t assocPbn; /* pbn of associate block */
fblock_t lbn; /* logical block number */
fpage_t nextFpn; /* next free page number, equal to */
/* # of pages per block if full block */
UINT16 index; /* index of this associate block in */
/* the global array */
UINT8 blkVer; /* block version */
int flags; /* FTL_ASSOC_FLAG_XXX */
void * pPgMap; /* page mapping of the lbn */
/*
* used associate blocks are roughly sorted by used-space ratio. This
* faciliate choosing the appropriate associate blocks for GC.
*/
DL_NODE listNode; /* node in associate blocks list */
DL_LIST * pList; /* which list this used node resides */
/*
* avl self balanced tree for fast searching since finding the
* associate block for a lbn is a much intensive operation.
* Besides, using avl tree has better scalability than list.
* On the negative side, each tree node consumes 4 more bytes
* than each list node and there needs a little more effort in
* balancing the tree.
*/
AVL_NODE avlNode;
struct assoc_blk_entry * pNext; /* list of blocks that are associated */
/* with the same lbn */
}ASSOC_BLK_ENTRY;
/* the page mapping for a logical block */
typedef struct lbn_pg_map
{
/*
* The page mapping are maintained in associate block cache on
* the LBN basis. Which means that either all the page mapping
* of a LBN are loaded in associate block cache or none of them
* are loaded.
*/
fblock_t lbn; /* logical block number */
ASSOC_BLK_ENTRY * pAssocBlks; /* pointer to associate blocks */
/* associate blocks */
ASSOC_PME * pPmeTbl; /* page mapping array which is indexed by LPN */
int index; /* index of the next free slot of */
/* <pAssocBlks>, */
/* it is also used as version of the */
/* associate blocks. */
int flags; /* RANDOM, SEQ (initial), BUSY (prevent it */
/* from reclaimed) */
FTL_ATOMIC32_T refCnt; /* reference count */
FTL_LOCK_T lock; /* lock it when the page map is being loaded */
/* have to protect the page mapping */
DL_NODE listNode; /* node of the list of associate block cache */
}LBN_PG_MAP;
#ifdef FTL_DEBUG
struct map_track { /* for debug purpose */
UINT32 pbn; /* track the page map */
UINT16 ppn; /* track the page map */
UINT16 status; /* page status */
};
#define FTL_DBG_PPN_BLANK 0xFF
#define FTL_DBG_PPN_FILL_BLANK 0xAA
#define FTL_DBG_PPN_VALID 0x55
struct ppn_track { /* for debug purpose */
UINT8 status; /* blank, filled blank, valid */
};
#endif /* FTL_DEBUG */
/* information of a hot block */
typedef struct hot_blk_info
{
fblock_t lbn; /* logical block number corresponding to pbn */
fblock_t pbn; /* physical block number of the hot data */
/* block */
fpage_t nextFpn; /* next free page number */
UINT8 blkVer; /* block version of data block */
blk_age_t blkAge; /* block age */
}HOT_BLK_INFO;
/* ftl managed device descriptor */
typedef struct ftl_desc
{
UINT32 ftlVersion; /* ftl version */
UINT32 ftlMagic; /* magic number: FTL_MAGIC */
int ftlMode; /* rw or rdonly */
int status; /* current status of the ftl device: */
/* FTL_INIT, FTL_READY, FTL_RECOVER */
#ifdef FTL_CLEAN_UNMOUNT
FTL_ATOMIC32_T refCnt; /* # of active users of the ftl device */
FTL_SEM_T unmountSem; /* wait on it for clean unmount */
#endif /* #ifdef FTL_CLEAN_UNMOUNT */
UINT32 ftlFlags; /* various flags */
/* format options */
UINT32 options; /* user configurable options */
/* user configurations */
MEM_BUDGET_T memBudget; /* configurable memory budget */
size_t dataCacheSize; /* configurable data cache size */
UINT32 usrConfig; /* user configurations */
struct ftl_bm_desc * pBm; /* pointer to BM instance */
/* FTL device internal layout */
/* meta blocks */
fblock_t blkStart; /* starting block number */
fblock_t nBlksAvail; /* total number of blocks available */
fblock_t metaBlkStart; /* start block number of meta area */
fblock_t nMetaBlks; /* total number of meta blocks */
fblock_t logBlkStart; /* start block number of log area */
fblock_t logBlkEnd; /* end block number of log area */
fblock_t nLogBlks; /* total number of log blocks */
fblock_t mapBlkStart; /* start block number of map area */
fblock_t nMapBlks; /* total number of map blocks */
/* data and associate blocks */
fblock_t dataBlkStart; /* start block number of data area */
fblock_t nDataBlks; /* total number of data blocks */
fblock_t nAssocBlks; /* total number of associate blocks */
/* grouping of data blocks */
UINT16 nGroups; /* total number of groups */
fblock_t nDataBlksPerGrp; /* how many data blocks are */
/* mapped in each group */
UINT16 lastGrpNo; /* total number of groups */
fblock_t nDataBlksLastGrp; /* how many data blocks are */
/* mapped in the last group */
/* replacement blocks: see bm_desc */
/*
* Following two arrays store the internal layout of a mapping and
* age page respectively throught various offsets and length.
* These values are calculated or filled at mount based on the
* geometry of the flash device. The index of these arrays are
* defined in two enumination type, mp_index and ap_index
* respectively.
*/
META_LAYOUT mpLayout[MP_IDX_MAX];
META_LAYOUT logLayout[LOG_IDX_MAX];
/* size of log/mp/ap unit */
fbsize_t logSize; /* size of each meta log */
fbsize_t updateLogSize; /* size of each meta log update */
fbsize_t mpSize; /* size of each mp */
fpage_t nPagesPerMp; /* # of pages per meta for a group */
fbsize_t nPagesPerLog; /* # of pages per log data */
FTL_OOB_TYPE oobType; /* oob type */
fpsize_t ftlOobSize; /* oob size used by FTL */
/* flash block access control */
FTL_LBN_CTRL_POOL lbnCtrlPool; /* lbn control pool */
FBIO_POOL fbioPool; /* fbio pool */
/*
* exclusive access control: Wear-leveling, garbage collection,
* and etc
*/
FTL_LOCK_T exclLock; /* huge exclusively access lock */
FTL_LOCK_T gcLock; /* use the exclLock */
FTL_LOCK_T wlLock; /* use the exclLock */
char * pPageBuf; /* page buffer for gc/wl */
struct ftl_data_cache * pDataCache; /* data cache support */
struct ftl_discard * pDiscard; /* discard support */
/* management of log area */
FTL_ADDR nextLogAddr; /* next location to write log */
FTL_META_LOG * pMetaLog; /* meta log */
META_LOG_BUF_INFO * pLogBuf; /* meta log buffer info */
/* management of map blocks */
FTL_LOCK_T mpLock; /* lock for hash operations */
UINT64 seqNo; /* Sequence number to track the */
/* mapping and age pages */
GRP_MP_INFO * pGrpMpTbl; /* the array address of meta pages */
/* for each group. The group number */
/* is the index of the array. */
UINT8 * pMpBlkBmp; /* bitmap to track the free map */
/* blocks */
UINT32 mpBlkBmpLen; /* length of the bitmap */
fblock_t nextFreeMapBlk;
FTL_LOCK_T * pGrpLocks; /* locks for each group */
/*
* management of write-through block map cache. It is organized in the
* form of list of nodes of type MP_BUF_INFO.
*/
void * pMpBufs; /* buffer for caching mapping page */
UINT16 nMpBufs; /* # of mapping page buffers */
DL_LIST mpList; /* used mapping page list - LRU */
FTL_SEM_T semCntMp; /* count semphore to track the page */
/* maps */
/*
* management of the associate blocks. The elementary type is
* ASSOC_BLK_ENTRY.
*/
FTL_LOCK_T assocLock; /* lock for associate block cache */
void * pAssocBlkMem; /* memory for the associate blocks */
DL_LIST usedAssocBlkList[FTL_NUM_ASSOC_BLK_LIST];
UINT16 spacePerList; /* used associate blocks list - */
/* sorted in space usage ratio */
DL_LIST freeAssocBlkList; /* free associate blocks list */
DL_LIST hskpAssocBlkList; /* house keeping associate */
/* blocks list */
DL_LIST hskpPgMapList; /* house keeping page map list */
AVL_TREE assocTree; /* associate block tree, lbn as key */
fblock_t nBlksPerHash; /* how many blocks are mapped to each */
/* hash list */
fblock_t * pAssocBlks; /* associate block numbers */
UINT16 maxAssocBlksPerLbn; /* maximum # of associate blocks */
/* for a lbn. */
/*
* management of assoicate page map cache. It is organized in the
* form of list of nodes of type LBN_PG_MAP
*/
void * pPgMapBufs; /* buffer for caching page mapping */
UINT16 nPgMapBufs; /* # of page mapping buffers */
DL_LIST pgMapList; /* page mapping buffer list in use - */
/* LRU */
DL_LIST freePgMapList; /* free page mapping buffer list */
FTL_SEM_T semCntPgMap; /* count semphore to track the page */
/* maps */
/* management of the cursor cache. */
FTL_LOCK_T cursorCacheLock;/* cursor cache lock */
UINT8 * pCursorTable; /* a full table tracking the next fpn */
/* for each lbn */
int cursorEntrySize;/* cursor entry size */
HOT_BLK_INFO * pHotDataBlks; /* hot data blocks info */
fblock_t nHotBlkEntry; /* # of hot block entries */
FTL_TASK_T svcTaskId; /* background task for WL, GC, etc */
int svcFlags; /* service flags */
FTL_SEM_T svcSyncSem; /* sync semophore to service task */
FTL_LOCK_T svcLock; /* service lock */
/*
* management of the age cache. It is organized in the form of
* list of nodes of type FTL_META_BUF.
*/
blk_age_t * pAgeOfAssocBlks;/* age of associate blocks */
int syncThresh; /* the threshold to flush age cache */
UINT64 ageSum; /* sum of age of all blocks */
UINT32 ageAvg; /* sum of age of all blocks */
UINT32 wlAgeThresh; /* a dynamic threshold to determine */
/* old blocks */
GRP_WL_INFO * pGrpWlInfo; /* group wear-leveling info */
GRP_WL_SORT * pGrpWlSort; /* for sorting group wl info */
FTL_LOCK_T wlListLock; /* wear-leveling list lock */
DL_LIST wlReqList; /* wear-leveling request list */
/* garbage collection stuff */
/*
* Internal implementations of read, write and ioctl of FTL. They
* might direct to different implemention based on different flash
* type. Both read and write will share the some code flow for
* translation.
*/
STATUS (*ftlRead) (struct ftl_desc * pFtl, struct ftl_bio * pFbio);
STATUS (*ftlWrite) (struct ftl_desc * pFtl, struct ftl_bio * pFbio);
STATUS (*ftlIoctl) (struct ftl_desc * pFtl, int cmd, FTL_IOCTL_ARG_T arg);
void * pBlkDev;
#ifdef FTL_DEBUG
struct {
FTL_ATOMIC64_T mountTicks;
FTL_ATOMIC64_T wrPageCnt;
FTL_ATOMIC64_T wrTicks; /* xbd visible */
FTL_ATOMIC64_T ftlWrTicks; /* ftl visible */
FTL_ATOMIC64_T rdPageCnt;
FTL_ATOMIC64_T rdTicks;
FTL_ATOMIC64_T discardPageCnt;
FTL_ATOMIC64_T discardTicks;
FTL_ATOMIC64_T cacheHitCnt;
FTL_ATOMIC64_T cacheMissCnt;
FTL_ATOMIC32_T gcSwitchCnt;
FTL_ATOMIC32_T gcCopyCnt;
FTL_ATOMIC32_T gcFullCnt;
FTL_ATOMIC32_T wlCnt;
FTL_ATOMIC32_T wlCntEnforced; /* enforced wl count for too old */
/* blocks */
FTL_ATOMIC32_T discardCnt; /* how many discards are accepted */
FTL_ATOMIC32_T discardCntFull; /* how many discarded blocks are */
/* fully discarded */
FTL_ATOMIC32_T discardCntPartial; /* how many discarded blocks are */
/* partially discarded */
FTL_ATOMIC32_T discardPagesPartial; /* how many pages are */
/* partially discarded */
FTL_ATOMIC32_T discardGcCnt;
FTL_ATOMIC32_T discardWlCnt;
FTL_ATOMIC32_T discardCacheDirtyPageCnt;
FTL_ATOMIC32_T discardInternalPageCnt;
/* meta cache */
FTL_ATOMIC32_T metaLogWrCnt;
FTL_ATOMIC32_T mpWrCnt;
FTL_ATOMIC32_T mpRdCnt;
FTL_ATOMIC32_T pgMapLoadCnt;
FTL_ATOMIC32_T cursorCacheHitCnt;
FTL_ATOMIC32_T cursorCacheMissCnt;
FTL_ATOMIC32_T mainBlkWritePageCnt;
FTL_ATOMIC32_T fillBlankPageCnt;
/* background task contribution */
FTL_ATOMIC32_T bgTaskWakeupCnt;
FTL_ATOMIC32_T bgTaskGcCnt;
FTL_ATOMIC32_T bgTaskWlCnt;
FTL_ATOMIC32_T bgTaskFlushCnt;
FTL_ATOMIC32_T bgTaskDiscardCnt;
FTL_ATOMIC32_T memUseHigh;
FTL_ATOMIC32_T memUseCur;
}dbgStat;
struct {
FTL_ATOMIC32_T curMemCost; /* total memory cost cost by ftl */
size_t ftlDesc;
size_t lbnCtrlPool;
size_t dataCache;
size_t blkMapCache;
size_t pageMapCache;
size_t cursorCache;
size_t assocBlks;
size_t metaLogBuf;
size_t grpMpTbl;
size_t grpLocks;
FTL_ATOMIC32_T discard;
size_t bbmtBuf;
size_t bbmtEntry;
}memStat;
struct map_track * pMapTrack;
struct ppn_track * pPpnTrack;
#endif
}FTL_DESC, *pFTL_DESC;
typedef struct ftl_dev_id /* ftl identify saved in flash */
{
/*
* endian field saves the endianess of all ftl meta data, 0 for
* little endian, 0xFF for big endian.
*/
UINT8 endian; /* endianess of saved meta data */
UINT8 pad[3];
UINT32 magic; /* ftl magic number */
UINT8 version; /* ftl version */
UINT8 selfLen; /* length of dev id itself in pages */
UINT8 pad1[2];
UINT16 options; /* ftl options */
UINT16 extFlags; /* extension flags, set to 0 if no */
/* flags are set */
/* geometry information */
UINT8 flashType; /* flash type */
UINT8 cellType; /* for nand flash only */
UINT16 pagesPerBlk; /* number of pages per block */
UINT64 totalSize; /* total size of this device */
UINT32 pageSize; /* page size in bytes */
UINT32 blkStart; /* starting block number */
UINT32 nBlks; /* total number of flash blocks */
UINT16 oobSize; /* oob size */
UINT16 oobSizeAvail; /* available oob size to FTL */
/*
* FTL layout, the following areas are not physical but logical blocks
* that has to be mapped to physical block through bad block map.
* The exceptions are the device id blocks and bbm blocks themselves.
*/
/* meta blocks */
UINT32 nBlksAvail; /* number of blocks available to ftl */
/* subtracted the bbm blocks */
UINT32 metaBlkStart; /* start block number of meta area */
UINT32 nMetaBlks; /* total number of meta blocks */
UINT32 logBlkStart; /* start block number of log area */
UINT32 nLogBlks; /* total number of log blocks */
UINT32 mapBlkStart; /* start block number of map area */
UINT32 nMapBlks; /* total number of map blocks */
/* data and associate blocks */
UINT32 dataBlkStart; /* start block number of data area */
UINT32 nDataBlks; /* total number of data blocks */
UINT32 nAssocBlks; /* total number of associate blocks */
UINT32 replBlkStart; /* starting replacement block */
UINT32 nReplBlks; /* # of replacement blocks */
UINT32 logLayout[LOG_IDX_MAX];
UINT32 mpLayout[MP_IDX_MAX];
/* grouping of data blocks */
UINT32 nGroups; /* total number of groups */
UINT32 nDataBlksPerGrp;/* how many data blocks are */
/* mapped in each group */
UINT16 oobType;
UINT16 ftlOobSize;
UINT32 logSize;
UINT32 mpSize;
UINT16 blkMarkPageNo; /* block mark page in block */
UINT16 blkMarkOffset; /* block mark offset in page */
/* static bbt offset */
UINT32 badBlkInfoOff; /* bad block info offset */
UINT32 badBlkInfoLen; /* bad block info length */
UINT32 stBbtOff; /* table of static bad blocks in bbm */
/* area */
UINT32 badBlkCnt; /* # of bad blocks in bbm area */
UINT32 stBbmtOff; /* static bad block map table */
UINT32 badBlkMapCnt; /* # of static bad block in non-bbm */
/* areas*/
UINT8 reserved[16];
UINT32 badBlkInfoChksum; /* bad block info checksum */
UINT32 devIdChksum; /* crc32 checksum */
}_FTL_PACK_ALIGN(4) FTL_DEV_ID; /* totally 188 bytes */
/* Mapping information descriptor flag */
#define FTL_MP_INFO_DESC_ERR_ADRS 0x01 /* incorrect physAddr */
#define FTL_MP_INFO_DESC_ERR_CNT 0x02 /* incorrect pageCnt */
/* function declarations */
STATUS ftlSaveIdentity (FTL_DESC * pFtl);
FTL_DEV_ID * ftlGetIdentity (void * pBm);
void ftlRelIdentity (FTL_DEV_ID * pFtlId);
STATUS ftlMountInternal (void * pBm);
STATUS ftlUnmountInternal (FTL_DESC * pFtl);
STATUS ftlUsrCfgInit (FTL_DESC * pFtl);
STATUS ftlDescInit (FTL_DESC * pFtl);
STATUS ftlDescCleanup (FTL_DESC * pFtl);
FTL_DESC * ftlDescGetByName (const char * pDevName);
/* ftl lbd module external routines */
int ftlLbdInit (FTL_DESC * pFtl);
int fbioInit (struct ftl_bio * pFbio);
int fpioInit (struct ftl_pio * pFpio);
int ftlLbdCleanup (FTL_DESC * pFtl);
int ftlLbdFlush (FTL_DESC * pFtl, BOOL isUnmount);
int ftlLbdDiscard (FTL_DESC * pFtl, FTL_DISCARD_INFO * pDiscardInfo);
int ftlLbnCtrlRel (FTL_DESC * pFtl, LBN_CTRL_ENTRY * pLbnCtrl);
int ftlFbioRel (FTL_DESC * pFtl, FTL_BIO * pFbio);
int ftlLbdRW (FTL_DESC * pFtl, faddr_t ftlIoAddr,
size_t ftlIoLen, char * pDataBuf, int rwFlag);
int ftlLbdBlkRW (FTL_DESC * pFtl, fblock_t blkAddr,
fbsize_t blkOff, fbsize_t ioLen,
char * pDataBuf, int rwFlag);
int ftlBlkRW (FTL_DESC * pFtl, FTL_BIO * pFbio, FTL_ADDR * pFromAddr,
fbsize_t ioLen, char * pDataBuf, int rwFlags);
LBN_CTRL_ENTRY * ftlLbnCtrlGet (FTL_DESC * pFtl, fblock_t lbn,
int rwFlag);
FTL_BIO * ftlFbioGet (FTL_DESC * pFtl, fblock_t lbn, int rwFlag);
LBN_CTRL_ENTRY * lbnCtrlFind (FTL_LBN_CTRL_POOL * pLbnCtrlPool,
fblock_t lbn);
int lbnCtrlLock (LBN_CTRL_ENTRY * pLbnCtrl, int flags);
int lbnCtrlUnlock (LBN_CTRL_ENTRY * pLbnCtrl);
int lbnCompare (AVL_NODE * pNode, void * pKey);
int fpioListAdd (DL_LIST * pList, DL_NODE * pNode);
int fpioListMove (DL_LIST * pDstList, DL_LIST * pSrcList,
DL_NODE * pNode);
_ftl_inline int fpioListDel (DL_LIST * pList, DL_NODE * pNode);
_ftl_inline int fpioListInit (DL_LIST * pList);
_ftl_inline FTL_PIO * fpioListNext (DL_LIST * pList, DL_NODE * pNode);
_ftl_inline FTL_PIO * fpioListFirst (DL_LIST * pList);
FTL_PIO * fpioListFind (DL_LIST * pList, fpage_t lpn);
/* ftl map module external routines */
int ftlMapInit (FTL_DESC * pFtl);
int ftlBlkMapInit (FTL_DESC * pFtl);
int ftlMapCleanup (FTL_DESC * pFtl);
int ftlCursorCacheFind (FTL_DESC * pFtl, fblock_t lbn,
HOT_BLK_INFO * pInfo);
int cursorInvalidate (FTL_DESC * pFtl, fblock_t lbn,
HOT_BLK_INFO * pInfo);
int ftlCursorCacheAdd (FTL_DESC * pFtl, HOT_BLK_INFO * pInfo, BOOL replace);
int ftlBlkMap (FTL_DESC * pFtl, fblock_t lbn, MAP_BLK_INFO * pBlkInfo);
MP_BUF_INFO * ftlBlkMapGet (FTL_DESC * pFtl, fblock_t lbn);
int ftlBlkMapRel (FTL_DESC * pFtl, MP_BUF_INFO * pMpBuf, BOOL dirty);
int ftlBlkMapLoad (FTL_DESC * pFtl, UINT16 grpNo, MP_BUF_INFO * pMpBuf);
int ftlBlkMapSave (FTL_DESC * pFtl,MP_BUF_INFO * pMpBuf);
MP_BUF_INFO * ftlMpBufGetDel (FTL_DESC * pFtl, UINT16 grpNo);
int ftlMpBufRel (FTL_DESC * pFtl, MP_BUF_INFO * pMpBuf);
int ftlAssocCacheInit (FTL_DESC * pFtl);
int ftlAssocCacheCleanup (FTL_DESC * pFtl);
int ftlFreeAssocBlkRel (FTL_DESC * pFtl, ASSOC_BLK_ENTRY * pAssocBlk);
ASSOC_BLK_ENTRY * ftlFreeAssocBlkGet (FTL_DESC * pFtl, int option);
ASSOC_BLK_ENTRY * ftlAssocBlkFind (FTL_DESC * pFtl, fblock_t lbn);
ASSOC_BLK_ENTRY * ftlGcGetUsedAssocBlk (FTL_DESC * pFtl,
LBN_CTRL_ENTRY ** ppLbnCtrl, BOOL bUrgent);
int ftlAssocBlkDel (FTL_DESC * pFtl, ASSOC_BLK_ENTRY * pAssocBlk);
LBN_PG_MAP * ftlAssocPgMapGet (FTL_DESC * pFtl, fblock_t lbn, int flags);
int ftlAssocBlkAdd (FTL_DESC * pFtl, ASSOC_BLK_ENTRY * pAssocBlk);
int ftlUsedAssocBlkListAdd (FTL_DESC * pFtl, ASSOC_BLK_ENTRY * pAssocBlk);
int ftlAssocPgMapRel (FTL_DESC * pFtl, LBN_PG_MAP * pPgMap);
int ftlAssocPgMapLoad (FTL_DESC * pFtl, ASSOC_BLK_ENTRY * pAssocBlk,
fblock_t lbn, LBN_PG_MAP * pPgMap);
STATUS ftlWlUpdatePgMap (FTL_DESC * pFtl, fblock_t lbn,
fblock_t oldPbn, fblock_t newPbn);
int ftlPgMapCleanup (FTL_DESC * pFtl, LBN_PG_MAP * pPgMap);
#ifdef obsolete
int ftlWriteBlkMark (FTL_DESC * pFtl, fblock_t blkNo, int blkType,
char * pBlkMarkBuf);
int ftlCheckBlkMark (FTL_DESC * pFtl, fblock_t blkNo, int blkType);
#endif /* obsolete */
int ftlWriteEraseMark (FTL_DESC * pFtl, fblock_t blkNo);
BOOL ftlCheckEraseMark (FTL_DESC * pFtl, fblock_t blkNo, BOOL bEraseBlk);
int ftlWriteBlkMark (FTL_DESC * pFtl, fblock_t blkNo, UINT8 blkMark);
BOOL ftlCheckBlkMark (FTL_DESC * pFtl, fblock_t blkNo, UINT8 blkMark);
int ftlWriteMetaLog (FTL_DESC * pFtl, META_LOG_BUF_INFO * pLogBuf);
int checkMeta (FTL_DESC * pFtl, char * pRawBuf);
int ftlLogNextGrpMpAddr (FTL_DESC * pFtl, fblock_t lbn);
int assocTreeCompare (AVL_NODE * pNode, void * pKey);
/* wear-leveling module external routines */
int ftlWlInit (FTL_DESC * pFtl);
int ftlWlCleanup (FTL_DESC * pFtl);
int ftlWearLeveling (FTL_DESC * pFtl, int option);
int ftlWlReqAdd (FTL_DESC * pFtl, ASSOC_BLK_ENTRY * pAssocBlk);
int ftlWlAssocBlk (FTL_DESC * pFtl, ASSOC_BLK_ENTRY * pAssocBlk);
int ftlWlMoveBlk (FTL_DESC * pFtl, fblock_t lbn, ASSOC_BLK_ENTRY * pAssocBlk);
_ftl_inline int ftlAgeThreshUpdate (FTL_DESC * pFtl);
_ftl_inline void ftlAvgAgeUpdate (FTL_DESC * pFtl);
int findYoungBlk (FTL_DESC * pFtl, fblock_t * pLbnIdx, blk_age_t * pAge);
int findGrpYoungBlk (FTL_DESC * pFtl, MP_BUF_INFO * pMpBuf,
fblock_t * pLbnIdx, blk_age_t * pAge, blk_age_t * pAgeSum);
BOOL ftlIsAssocBlkTooOld (FTL_DESC * pFtl, ASSOC_BLK_ENTRY * pAssocBlk);
int ftlSvcTaskCreate (FTL_DESC * pFtl);
int ftlSvcTaskDelete (FTL_DESC * pFtl);
/* garbage-collection module external routines */
int ftlGarbageCollection (FTL_DESC * pFtl, BOOL bUrgent);
int ftlGcMergeUrgent (FTL_DESC * pFtl, LBN_PG_MAP * pPgMap,
HOT_BLK_INFO * pDataBlkInfo);
int ftlGcMergeNormal (FTL_DESC * pFtl, LBN_PG_MAP * pPgMap,
HOT_BLK_INFO * pDataBlkInfo);
/* discard support */
int ftlDiscardInit (FTL_DESC * pFtl);
int ftlDiscardCleanup (FTL_DESC * pFtl);
int ftlDiscard (FTL_DESC * pFtl, int flags);
int ftlDiscardBlk (FTL_DESC * pFtl, FTL_BLK_DISCARD_INFO * pBlkDiscard);
int ftlDiscardCheck (FTL_DESC * pFtl, fblock_t lbn,
fpage_t fromLpn, fpage_t endLpn);
int ftlDiscardUpdate (FTL_DESC * pFtl, fblock_t lbn,
fpage_t fromLpn, fpage_t endLpn);
FTL_DISCARD_NODE * ftlDiscardFind (FTL_DESC * pFtl, fblock_t lbn);
/* misc */
int ftlOobInit (FTL_DESC * pFtl, char * pOobBuf, UINT8 oobVer);
int ftlOobSet (FTL_DESC * pFtl, char * pOobBuf, UINT8 blkVer,
fblock_t lbn, fpage_t lpn, blk_age_t age);
int ftlOobSetFull (FTL_DESC * pFtl, char * pOobBuf, UINT8 blkVer,
fblock_t lbn, fpage_t lpn, blk_age_t age, BOOL blank, BOOL error);
int ftlOobSetBlkInfo (FTL_DESC * pFtl, char * pOobBuf, UINT8 blkVer,
blk_age_t age);
int ftlOobChksum (FTL_DESC * pFtl, char * pOobBuf);
fblock_t mapBlkAlloc (FTL_DESC * pFtl);
void mapBlkFree (FTL_DESC * pFtl, fblock_t blkNo);
FTL_OOB_LARGE * bufToLargeOob (FTL_DESC * pFtl, char * pBuf,
FTL_OOB_LARGE * pOobLarge);
FTL_OOB_SMALL * bufToSmallOob (FTL_DESC * pFtl, char * pBuf);
int checkPattern (const char * pBuf, size_t dataLen, char pattern, int * pBits);
int setPattern (char * pBuf, size_t dataLen, char pattern);
int ftlEraseBlk (FTL_DESC * pFtl, fblock_t blkNo, int blkType,
int flags);
int ftlOobFlashToRam (FTL_DESC * pFtl, char * pOobBuf, FTL_OOB_RAM * pOobRam);
int blkVerCompare (UINT8 blkVer1, UINT8 blkVer2, BOOL major);
/* global configuration options */
extern BOOL ftlBgSvcTaskEnabled;
extern MEM_BUDGET_T ftlMemBudgetCfg;
extern BOOL ftlAutoMountEnabled;
extern BOOL ftlAutoRecvErrorEnabled;
extern BOOL ftlCacheEnabled;
extern size_t ftlCacheSize;
extern BOOL ftlDiscardEnabled;
/* declaration of ftl cache component function pointers */
IMPORT int (* _func_ftlCacheInit) (FTL_DESC * pFtl);
IMPORT int (* _func_ftlCacheCleanup) (FTL_DESC * pFtl);
IMPORT int (* _func_ftlCacheBlkRW) (FTL_DESC * pFtl, fblock_t blkAddr,
fbsize_t blkOff, fbsize_t ioLen, char * pDataBuf,
int rwFlag);
IMPORT int (* _func_ftlCacheFlush) (FTL_DESC * pFtl, int option);
IMPORT int (* _func_ftlCacheDiscard) (FTL_DESC * pFtl,
FTL_BLK_DISCARD_INFO * pBlkDiscardInfo);
IMPORT STATUS (* _func_ftlCacheCheckFlush) (FTL_DESC * pFtl);
/* declaration of ftl discard component function pointers */
IMPORT int (* _func_ftlDiscardInit) (FTL_DESC * pFtl);
IMPORT int (* _func_ftlDiscardCleanup) (FTL_DESC * pFtl);
IMPORT int (* _func_ftlDiscard) (FTL_DESC * pFtl, int flags);
IMPORT int (* _func_ftlDiscardBlk) (FTL_DESC * pFtl,
FTL_BLK_DISCARD_INFO * pBlkDiscard);
IMPORT int (* _func_ftlDiscardCheck) (FTL_DESC * pFtl, fblock_t lbn,
fpage_t fromLpn, fpage_t endLpn);
IMPORT int (* _func_ftlDiscardUpdate) (FTL_DESC * pFtl, fblock_t lbn,
fpage_t fromLpn, fpage_t endLpn);
IMPORT FTL_DISCARD_NODE * (* _func_ftlDiscardFind) (FTL_DESC * pFtl,
fblock_t lbn);
#ifdef FTL_CLEAN_UNMOUNT
int ftlDevGet (FTL_DESC * pFtl);
int ftlDevPut (FTL_DESC * pFtl);
#endif /* FTL_CLEAN_UNMOUNT */
#ifdef FTL_DEBUG
IMPORT UINT32 ftlDbgFlags;
#define FTL_DBG_PAGE_BLANK 0xFF
#define FTL_DBG_PAGE_VALID 0x5A
#define FTL_DBG_PAGE_DISCARDED 0x0
int ftlDbgPageMapUpdate (FTL_DESC * pFtl, fblock_t lbn,
fpage_t lpn, fblock_t pbn, fpage_t ppn);
int ftlDbgBlkMapUpdate (FTL_DESC * pFtl, fblock_t lbn,
fblock_t pbn);
int ftlDbgPageStatusUpdate (FTL_DESC * pFtl, fblock_t lbn,
fpage_t lpn, fpage_t nPages, UINT8 status);
int ftlDbgPageMapShow (const char * pDevName, fblock_t lbn,
fpage_t lpn, fpage_t nPages);
int ftlDbgPpnStatusUpdate (FTL_DESC * pFtl, fblock_t pbn,
fpage_t ppn, fpage_t nPages, UINT8 status);
int ftlDbgPpnStatusShow (const char * pDevName, fblock_t pbn,
fpage_t ppn, fpage_t nPages);
#endif /* FTL_DEBUG */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __INCftlLibPh */