obj-m := $(YAFFS_O)
- yaffs2-objs := yaffs_mtdif.o yaffs_mtdif2_single.o
- yaffs2-objs += yaffs_mtdif1_single.o yaffs_packedtags1.o
+ yaffs2-objs := yaffs_mtdif_single.o
+ yaffs2-objs += yaffs_packedtags1.o
yaffs2-objs += yaffs_ecc.o yaffs_vfs_single.o yaffs_guts.o
yaffs2-objs += yaffs_packedtags2.o
yaffs2-objs += yaffs_tagscompat.o
+ yaffs2-objs += yaffs_tagsmarshall.o
yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o
yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o yaffs_nameval.o
yaffs2-objs += yaffs_allocator.o yaffs_bitmap.o yaffs_attribs.o
yaffs2-objs += yaffs_verify.o
yaffs2-objs += yaffs_summary.o
- yaffs2multi-objs := yaffs_mtdif.o yaffs_mtdif2_multi.o
- yaffs2multi-objs += yaffs_mtdif1_multi.o yaffs_packedtags1.o
+ yaffs2multi-objs := yaffs_mtdif_multi.o
+ yaffs2multi-objs += yaffs_packedtags1.o
yaffs2multi-objs += yaffs_ecc.o yaffs_vfs_multi.o yaffs_guts.o
yaffs2multi-objs += yaffs_packedtags2.o
yaffs2multi-objs += yaffs_tagscompat.o
+ yaffs2multi-objs += yaffs_tagsmarshall.o
yaffs2multi-objs += yaffs_checkptrw.o yaffs_nand.o
yaffs2multi-objs += yaffs_checkptrw.o yaffs_nand.o yaffs_nameval.o
yaffs2multi-objs += yaffs_allocator.o yaffs_bitmap.o yaffs_attribs.o
+++ /dev/null
-# Makefile for YAFFS direct test
-#
-#
-# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
-#
-# Copyright (C) 2003-2010 Aleph One Ltd.
-#
-#
-# Created by Charles Manning <charles@aleph1.co.uk>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation.
-#
-# NB Warning this Makefile does not include header dependencies.
-#
-# $Id: Makefile,v 1.24 2010-02-17 02:18:57 charles Exp $
-
-#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
-
-CFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_YAFFS2 -D CONFIG_YAFFS_DEFINES_TYPES
-CFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES -DNO_Y_INLINE
-CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS) -Werror=strict-aliasing
-#CFLAGS += -fno-strict-aliasing
-CFLAGS += -O0
-#CFLAGS += -DVALGRIND_TEST
-#CFLAGS += -DCONFIG_YAFFS_CASE_INSENSITIVE
-
-CFLAGS+= -Wshadow -Werror=pointer-arith -Werror=write-strings
-CFLAGS+= -Werror=strict-prototypes -Werror=missing-parameter-type
-CFLAGS+= -Werror=redundant-decls -Werror=nested-externs -Winline
-CFLAGS+= -Werror=undef
-
-CFLAGS+= -DCONFIG_YAFFS_USE_PTHREADS -lpthread
-
-
-COMMONTESTOBJS = yaffscfg2k.o yaffs_osglue.o yaffs_hweight.o \
- yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
- yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
- yaffs_tagscompat.o yaffs_packedtags2.o yaffs_nand.o \
- yaffs_checkptrw.o yaffs_qsort.o\
- yaffs_nameval.o yaffs_attribs.o \
- yaffs_norif1.o ynorsim.o \
- yaffs_allocator.o \
- yaffs_bitmap.o \
- yaffs_yaffs1.o \
- yaffs_yaffs2.o \
- yaffs_verify.o \
- yaffs_summary.o
-
-# yaffs_checkptrwtest.o\
-
-
-YAFFSDIRECTSYMLINKS = \
- yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h \
- yaffs_tagscompat.c yaffs_tagscompat.h \
- yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h \
- yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.h \
- yaffs_checkptrw.h yaffs_checkptrw.c \
- yaffs_nameval.c yaffs_nameval.h \
- yaffs_trace.h yaffs_attribs.h \
- yaffs_allocator.c yaffs_allocator.h \
- yaffs_yaffs1.c yaffs_yaffs1.h \
- yaffs_yaffs2.c yaffs_yaffs2.h \
- yaffs_bitmap.c yaffs_bitmap.h \
- yaffs_verify.c yaffs_verify.h \
- yaffs_summary.c yaffs_summary.h \
- yaffsfs.c yaffs_flashif.h yaffs_flashif2.h\
- yaffsfs.h yaffs_osglue.h ydirectenv.h \
- yaffscfg.h yaffs_list.h \
- yaffs_qsort.c yportenv.h yaffs_attribs.c \
- yaffs_nandif.c yaffs_nandif.h yaffs_nandemul2k.h \
- yaffs_hweight.h yaffs_hweight.c \
-
-
-
-DIRECTTESTOBJS = $(COMMONTESTOBJS) dtest.o
-
-BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o
-
-ALLOBJS = $(sort $(DIRECTTESTOBJS) $(YAFFSTESTOBJS))
-
-TARGETS = directtest2k
-
-all: $(TARGETS)
-
-$(ALLOBJS): %.o: %.c
- gcc -c $(CFLAGS) -o $@ $<
-
-
-$(YAFFSDIRECTSYMLINKS):
- ln -s ../$@ $@
-
-
-directtest2k: $(YAFFSDIRECTSYMLINKS) $(DIRECTTESTOBJS)
- gcc -o $@ $(DIRECTTESTOBJS)
-
-yaffs_test: $(YAFFSDIRECTSYMLINKS) $(YAFFSTESTOBJS)
- gcc -o $@ $(YAFFSTESTOBJS)
-
-
-boottest: $(YAFFSDIRECTSYMLINKS) $(BOOTTESTOBJS)
- gcc -o $@ $(BOOTTESTOBJS)
-
-
-clean:
- rm -f $(TARGETS) $(ALLOBJS) core $(YAFFSDIRECTSYMLINKS)
+++ /dev/null
-/*
- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * This provides a YAFFS nand emulation on a file for emulating 2kB pages.
- * This is only intended as test code to test persistence etc.
- */
-
-const char *yaffs_flashif2_c_version = "$Id: yaffs_fileem2k.c,v 1.24 2010-02-18 01:18:04 charles Exp $";
-
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-
-#include "yaffs_flashif2.h"
-#include "yaffs_guts.h"
-#include "yaffs_fileem2k.h"
-#include "yaffs_packedtags2.h"
-
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-
-
-#define REPORT_ERROR 0
-
-typedef struct
-{
- u8 data[PAGE_SIZE]; // Data + spare
-} yflash_Page;
-
-typedef struct
-{
- yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
-
-} yflash_Block;
-
-
-
-#define MAX_HANDLES 20
-#define BLOCKS_PER_HANDLE (32*8)
-
-typedef struct
-{
- int handle[MAX_HANDLES];
- int nBlocks;
-} yflash_Device;
-
-static yflash_Device filedisk;
-
-int yaffs_test_partial_write = 0;
-
-extern int random_seed;
-extern int simulate_power_failure;
-static int remaining_ops;
-static int nops_so_far;
-
-int ops_multiplier;
-
-
-static void yflash2_MaybePowerFail(unsigned int nand_chunk, int failPoint)
-{
-
- nops_so_far++;
-
-
- remaining_ops--;
- if(simulate_power_failure &&
- remaining_ops < 1){
- printf("Simulated power failure after %d operations\n",nops_so_far);
- printf(" power failed on nand_chunk %d, at fail point %d\n",
- nand_chunk, failPoint);
- exit(0);
- }
-}
-
-
-
-
-
-static u8 localBuffer[PAGE_SIZE];
-
-static char *NToName(char *buf,int n)
-{
- sprintf(buf,"emfile-2k-%d",n);
- return buf;
-}
-
-static char dummyBuffer[BLOCK_SIZE];
-
-static int GetBlockFileHandle(int n)
-{
- int h;
- int requiredSize;
-
- char name[40];
- NToName(name,n);
- int fSize;
- int i;
-
- h = open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
- if(h >= 0){
- fSize = lseek(h,0,SEEK_END);
- requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
- if(fSize < requiredSize){
- for(i = 0; i < BLOCKS_PER_HANDLE; i++)
- if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
- return -1;
-
- }
- }
-
- return h;
-
-}
-
-static int CheckInit(void)
-{
- static int initialised = 0;
- int i;
-
- int blk;
-
-
- if(initialised)
- {
- return YAFFS_OK;
- }
-
- initialised = 1;
-
-
- srand(random_seed);
- remaining_ops = (rand() % 1000) * 5;
- memset(dummyBuffer,0xff,sizeof(dummyBuffer));
-
-
-
- filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
-
- for(i = 0; i < MAX_HANDLES; i++)
- filedisk.handle[i] = -1;
-
- for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
- filedisk.handle[i] = GetBlockFileHandle(i);
-
-
- return 1;
-}
-
-
-int yflash2_GetNumberOfBlocks(void)
-{
- CheckInit();
-
- return filedisk.nBlocks;
-}
-
-int yflash2_WriteChunkWithTagsToNAND(struct yaffs_dev *dev,int nand_chunk,const u8 *data, const struct yaffs_ext_tags *tags)
-{
- int written;
- int pos;
- int h;
- int i;
- int nRead;
- int error;
-
- yaffs_trace(YAFFS_TRACE_MTD, "write chunk %d data %p tags %p",nand_chunk, data, tags);
-
- CheckInit();
-
-
- if(dev->param.inband_tags){
-
- struct yaffs_packed_tags2_tags_only * pt2tp;
- pt2tp = (struct yaffs_packed_tags2_tags_only *)&data[dev->data_bytes_per_chunk];
- yaffs_pack_tags2_tags_only(pt2tp,tags);
-
- pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
- h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
-
- lseek(h,pos,SEEK_SET);
- written = write(h,data,dev->param.total_bytes_per_chunk);
-
-
- if(yaffs_test_partial_write){
- close(h);
- exit(1);
- }
-
- if(written != dev->param.total_bytes_per_chunk) return YAFFS_FAIL;
-
-
- }
-
- else {
- /* First do a write of a partial page */
- int n_partials;
- int bpos;
-
- if(data)
- {
- pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
- h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
-
-
- memcpy(localBuffer,data, dev->data_bytes_per_chunk);
-
- n_partials = rand()%20;
-
- for(i = 0; i < n_partials; i++){
- bpos = rand() % dev->data_bytes_per_chunk;
-
- localBuffer[bpos] |= (1 << (rand() & 7));
- }
-
- if(REPORT_ERROR && memcmp(localBuffer,data,dev->data_bytes_per_chunk))
- printf("nand simulator: data does not match\n");
-
- lseek(h,pos,SEEK_SET);
- written = write(h,localBuffer,dev->data_bytes_per_chunk);
-
- if(yaffs_test_partial_write){
- close(h);
- exit(1);
- }
-
-
- if(written != dev->data_bytes_per_chunk) return YAFFS_FAIL;
- }
- // yflash2_MaybePowerFail(nand_chunk,1);
-
- if(tags)
- {
- pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
- h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
-
- lseek(h,pos,SEEK_SET);
-
- if( 0 && dev->param.is_yaffs2)
- {
-
- written = write(h,tags,sizeof(struct yaffs_ext_tags));
- if(written != sizeof(struct yaffs_ext_tags)) return YAFFS_FAIL;
- }
- else
- {
- struct yaffs_packed_tags2 pt;
- yaffs_pack_tags2(&pt,tags, !dev->param.no_tags_ecc);
- u8 * ptab = (u8 *)&pt;
-
- nRead = read(h,localBuffer,sizeof(pt));
- for(i = error = 0; REPORT_ERROR && i < sizeof(pt) && !error; i++){
- if(localBuffer[i] != 0xFF){
- printf("nand simulation: chunk %d oob byte %d was %0x2\n",
- nand_chunk,i,localBuffer[i]);
- error = 1;
- }
- }
-
- for(i = 0; i < sizeof(pt); i++)
- localBuffer[i] &= ptab[i];
-
- n_partials = rand()% sizeof(pt);
-
- for(i = 0; i < n_partials; i++){
- bpos = rand() % sizeof(pt);
-
- localBuffer[bpos] |= (1 << (rand() & 7));
- }
-
- if(REPORT_ERROR && memcmp(localBuffer,&pt,sizeof(pt)))
- printf("nand sim: tags corruption\n");
-
- lseek(h,pos,SEEK_SET);
-
- written = write(h,localBuffer,sizeof(pt));
- if(written != sizeof(pt)) return YAFFS_FAIL;
- }
- }
-
- //yflash2_MaybePowerFail(nand_chunk,2);
-
- /* Next do the whole write */
- if(data)
- {
- pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
- h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
-
-
- memset(localBuffer,0xFF, PAGE_SIZE);
- for(i = 0; i < dev->data_bytes_per_chunk; i++){
- localBuffer[i] &= data[i];
- }
-
- if(REPORT_ERROR && memcmp(localBuffer,data,dev->data_bytes_per_chunk))
- printf("nand simulator: data does not match\n");
-
- lseek(h,pos,SEEK_SET);
- written = write(h,localBuffer,dev->data_bytes_per_chunk);
-
- if(yaffs_test_partial_write){
- close(h);
- exit(1);
- }
-
-
- if(written != dev->data_bytes_per_chunk) return YAFFS_FAIL;
- }
-
- if(tags)
- {
- pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
- h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
-
- lseek(h,pos,SEEK_SET);
-
- if( 0 && dev->param.is_yaffs2)
- {
-
- written = write(h,tags,sizeof(struct yaffs_ext_tags));
- if(written != sizeof(struct yaffs_ext_tags)) return YAFFS_FAIL;
- }
- else
- {
- struct yaffs_packed_tags2 pt;
- yaffs_pack_tags2(&pt,tags,!dev->param.no_tags_ecc);
- u8 * ptab = (u8 *)&pt;
-
- nRead = read(h,localBuffer,sizeof(pt));
- for(i = error = 0; REPORT_ERROR && i < sizeof(pt) && !error; i++){
- if(localBuffer[i] != 0xFF){
- printf("nand simulation: chunk %d oob byte %d was %0x2\n",
- nand_chunk,i,localBuffer[i]);
- error = 1;
- }
- }
-
- for(i = 0; i < sizeof(pt); i++)
- localBuffer[i] &= ptab[i];
-
- if(REPORT_ERROR && memcmp(localBuffer,&pt,sizeof(pt)))
- printf("nand sim: tags corruption\n");
-
- lseek(h,pos,SEEK_SET);
-
- written = write(h,localBuffer,sizeof(pt));
- if(written != sizeof(pt)) return YAFFS_FAIL;
- }
- }
-
- yflash2_MaybePowerFail(nand_chunk,3);
-
- }
- return YAFFS_OK;
-
-}
-
-int yaffs_check_all_ff(const u8 *ptr, int n)
-{
- while(n)
- {
- n--;
- if(*ptr!=0xFF) return 0;
- ptr++;
- }
- return 1;
-}
-
-
-static int fail300 = 1;
-static int fail320 = 1;
-
-static int failRead10 = 2;
-
-int yflash2_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev,int nand_chunk, u8 *data, struct yaffs_ext_tags *tags)
-{
- int nread;
- int pos;
- int h;
- int localData = 0;
- int retval = YAFFS_OK;
- int nRead;
-
- yaffs_trace(YAFFS_TRACE_MTD,"read chunk %d data %p tags %p",nand_chunk, data, tags);
-
- CheckInit();
-
-
-
-
- if(dev->param.inband_tags){
- /* Got to suck the tags out of the data area */
- if(!data) {
- localData=1;
- data = yaffs_get_temp_buffer(dev);
- }
-
-
- struct yaffs_packed_tags2_tags_only * pt2tp;
- pt2tp = (struct yaffs_packed_tags2_tags_only *)&data[dev->data_bytes_per_chunk];
-
-
- pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
- h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
-
- lseek(h,pos,SEEK_SET);
-
- nRead = read(h, data,dev->param.total_bytes_per_chunk);
-
- yaffs_unpack_tags2_tags_only(tags,pt2tp);
-
- if(nread != dev->param.total_bytes_per_chunk)
- retval = YAFFS_FAIL;
-
- if(localData)
- yaffs_release_temp_buffer(dev, data);
-
-
-
- }
-
- else {
-
- if(data)
- {
-
- pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
- h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
- lseek(h,pos,SEEK_SET);
- nread = read(h,data,dev->data_bytes_per_chunk);
-
-
- if(nread != dev->data_bytes_per_chunk)
- retval = YAFFS_FAIL;
- }
-
- if(tags)
- {
- pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
- h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
- lseek(h,pos,SEEK_SET);
-
- if(0 && dev->param.is_yaffs2)
- {
- nread= read(h,tags,sizeof(struct yaffs_ext_tags));
- if(nread != sizeof(struct yaffs_ext_tags))
- retval = YAFFS_FAIL;
- if(yaffs_check_all_ff((u8 *)tags, sizeof(struct yaffs_ext_tags)))
- memset(tags, 0, sizeof(struct yaffs_ext_tags));
- else
- tags->chunk_used = 1;
- }
- else
- {
- struct yaffs_packed_tags2 pt;
- nread= read(h,&pt,sizeof(pt));
- yaffs_unpack_tags2(tags,&pt, !dev->param.no_tags_ecc);
-#ifdef SIMULATE_FAILURES
- if((nand_chunk >> 6) == 100) {
- if(fail300 && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR){
- tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
- fail300 = 0;
- }
- }
-
- if((nand_chunk >> 6) == 110) {
- if(fail320 && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR){
- tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
- fail320 = 0;
- }
- }
-#endif
- if(failRead10>0 && nand_chunk == 10){
- failRead10--;
- nread = 0;
- }
-
- if(nread != sizeof(pt))
- retval = YAFFS_FAIL;
- }
- }
- }
-
-
-
- return retval;
-
-}
-
-
-int yflash2_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no)
-{
- int written;
- int h;
-
- struct yaffs_packed_tags2 pt;
-
- CheckInit();
-
- memset(&pt,0,sizeof(pt));
- h = filedisk.handle[(block_no / ( BLOCKS_PER_HANDLE))];
- lseek(h,((block_no % BLOCKS_PER_HANDLE) * dev->param.chunks_per_block) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
- written = write(h,&pt,sizeof(pt));
-
- if(written != sizeof(pt)) return YAFFS_FAIL;
-
-
- return YAFFS_OK;
-
-}
-
-int yflash2_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
-{
-
- int i;
- int h;
-
- CheckInit();
-
- //printf("erase block %d\n",blockNumber);
-
- if(blockNumber == 320)
- fail320 = 1;
-
- if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
- {
- yaffs_trace(YAFFS_TRACE_ALWAYS,"Attempt to erase non-existant block %d",blockNumber);
- return YAFFS_FAIL;
- }
- else
- {
-
- u8 pg[PAGE_SIZE];
- int syz = PAGE_SIZE;
- int pos;
-
- memset(pg,0xff,syz);
-
-
- h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
- lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->param.chunks_per_block) * PAGE_SIZE,SEEK_SET);
- for(i = 0; i < dev->param.chunks_per_block; i++)
- {
- write(h,pg,PAGE_SIZE);
- }
- pos = lseek(h, 0,SEEK_CUR);
-
- return YAFFS_OK;
- }
-
-}
-
-int yflash2_InitialiseNAND(struct yaffs_dev *dev)
-{
- CheckInit();
-
- return YAFFS_OK;
-}
-
-
-
-
-int yflash2_QueryNANDBlock(struct yaffs_dev *dev, int block_no, enum yaffs_block_state *state, u32 *seq_number)
-{
- struct yaffs_ext_tags tags;
- int chunkNo;
-
- *seq_number = 0;
-
- chunkNo = block_no * dev->param.chunks_per_block;
-
- yflash2_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
- if(tags.block_bad)
- {
- *state = YAFFS_BLOCK_STATE_DEAD;
- }
- else if(!tags.chunk_used)
- {
- *state = YAFFS_BLOCK_STATE_EMPTY;
- }
- else if(tags.chunk_used)
- {
- *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
- *seq_number = tags.seq_number;
- }
- return YAFFS_OK;
-}
-
+++ /dev/null
-/*
- * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1 as
- * published by the Free Software Foundation.
- *
- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
- */
-
-#ifndef __FILEEM2K_H__
-#define __FILEEM2K_H__
-
-#if 1
-
-#define SIZE_IN_MB 32
-/* #define SIZE_IN_MB 128 */
-
-#define PAGE_DATA_SIZE (2048)
-#define PAGE_SPARE_SIZE (64)
-#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
-#define PAGES_PER_BLOCK (64)
-#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK)
-#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE))
-#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE)
-#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB)
-
-#else
-
-#define SIZE_IN_MB 128
-#define PAGE_DATA_SIZE (512)
-#define SPARE_SIZE (16)
-#define PAGE_SIZE (PAGE_DATA_SIZE + SPARE_SIZE)
-#define PAGES_PER_BLOCK (32)
-#define BLOCK_DATA_SIZE (PAGE_SIZE * PAGES_PER_BLOCK)
-#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE))
-#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE)
-#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB)
-
-#endif
-
-
-int yflash2_GetNumberOfBlocks(void);
-
-#endif
-
+++ /dev/null
-/*
- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * yaffscfg2k.c The configuration for the "direct" use of yaffs.
- *
- * This file is intended to be modified to your requirements.
- * There is no need to redistribute this file.
- */
-
-#include "yaffscfg.h"
-#include "yaffs_guts.h"
-#include "yaffsfs.h"
-#include "yaffs_fileem2k.h"
-#include "yaffs_nandemul2k.h"
-#include "yaffs_norif1.h"
-#include "yaffs_trace.h"
-#include "yaffs_osglue.h"
-
-
-#include <errno.h>
-
-unsigned yaffs_trace_mask =
-
- YAFFS_TRACE_SCAN |
- YAFFS_TRACE_GC |
- YAFFS_TRACE_ERASE |
- YAFFS_TRACE_ERROR |
- YAFFS_TRACE_TRACING |
- YAFFS_TRACE_ALLOCATE |
- YAFFS_TRACE_BAD_BLOCKS |
- YAFFS_TRACE_VERIFY |
-
- 0;
-
-
-
-// Configuration
-
-#include "yaffs_ramdisk.h"
-#include "yaffs_flashif.h"
-#include "yaffs_flashif2.h"
-#include "yaffs_nandemul2k.h"
-
-struct yaffs_dev ram1Dev;
-struct yaffs_dev flashDev;
-struct yaffs_dev m18_1Dev;
-
-int yaffs_start_up(void)
-{
- static int start_up_called = 0;
-
- if(start_up_called)
- return;
- start_up_called = 1;
-
- // Stuff to configure YAFFS
- // Stuff to initialise anything special (eg lock semaphore).
- yaffsfs_OSInitialisation();
-
- // Set up devices
- // /ram1 ram, yaffs1
- memset(&ram1Dev,0,sizeof(ram1Dev));
- ram1Dev.param.name = "ram1";
- ram1Dev.param.total_bytes_per_chunk = 512;
- ram1Dev.param.chunks_per_block = 32;
- ram1Dev.param.n_reserved_blocks = 2; // Set this smaller for RAM
- ram1Dev.param.start_block = 0; // Can use block 0
- ram1Dev.param.end_block = 127; // Last block in 2MB.
- //ram1Dev.param.use_nand_ecc = 1;
- ram1Dev.param.n_caches = 0; // Disable caching on this device.
- ram1Dev.driver_context = (void *) 0; // Used to identify the device in fstat.
- ram1Dev.param.write_chunk_tags_fn = yramdisk_wr_chunk;
- ram1Dev.param.read_chunk_tags_fn = yramdisk_rd_chunk;
- ram1Dev.param.erase_fn = yramdisk_erase;
- ram1Dev.param.initialise_flash_fn = yramdisk_initialise;
-
- yaffs_add_device(&ram1Dev);
-
- // /M18-1 yaffs1 on M18 nor sim
- memset(&m18_1Dev,0,sizeof(m18_1Dev));
- m18_1Dev.param.name = "M18-1";
- m18_1Dev.param.total_bytes_per_chunk = 1024;
- m18_1Dev.param.chunks_per_block =248;
- m18_1Dev.param.n_reserved_blocks = 2;
- m18_1Dev.param.start_block = 0; // Can use block 0
- m18_1Dev.param.end_block = 31; // Last block
- m18_1Dev.param.use_nand_ecc = 0; // use YAFFS's ECC
- m18_1Dev.param.n_caches = 10; // Use caches
- m18_1Dev.param.disable_soft_del = 1;
- m18_1Dev.driver_context = (void *) 1; // Used to identify the device in fstat.
- m18_1Dev.param.write_chunk_fn = ynorif1_WriteChunkToNAND;
- m18_1Dev.param.read_chunk_fn = ynorif1_ReadChunkFromNAND;
- m18_1Dev.param.erase_fn = ynorif1_EraseBlockInNAND;
- m18_1Dev.param.initialise_flash_fn = ynorif1_InitialiseNAND;
- m18_1Dev.param.deinitialise_flash_fn = ynorif1_Deinitialise_flash_fn;
-
-// m18_1Dev.param.disable_soft_del = 1;
-
- yaffs_add_device(&m18_1Dev);
-
- // /yaffs2 yaffs2 file emulation
- // 2kpage/64chunk per block
- //
- memset(&flashDev,0,sizeof(flashDev));
- flashDev.param.name = "yaffs2";
- flashDev.param.total_bytes_per_chunk = 2048;
- flashDev.param.chunks_per_block = 64;
- flashDev.param.n_reserved_blocks = 5;
- flashDev.param.inband_tags = 0;
- flashDev.param.start_block = 0;
- flashDev.param.end_block = yflash2_GetNumberOfBlocks()-1;
- flashDev.param.is_yaffs2 = 1;
- flashDev.param.use_nand_ecc=1;
- flashDev.param.wide_tnodes_disabled=0;
- flashDev.param.refresh_period = 1000;
- flashDev.param.n_caches = 10; // Use caches
- flashDev.driver_context = (void *) 2; // Used to identify the device in fstat.
- flashDev.param.write_chunk_tags_fn = yflash2_WriteChunkWithTagsToNAND;
- flashDev.param.read_chunk_tags_fn = yflash2_ReadChunkWithTagsFromNAND;
- flashDev.param.erase_fn = yflash2_EraseBlockInNAND;
- flashDev.param.initialise_flash_fn = yflash2_InitialiseNAND;
- flashDev.param.bad_block_fn = yflash2_MarkNANDBlockBad;
- flashDev.param.query_block_fn = yflash2_QueryNANDBlock;
- flashDev.param.enable_xattr = 1;
-
- yaffs_add_device(&flashDev);
-
-// todo yaffs_initialise(yaffsfs_config);
-
- return 0;
-}
-
-
-
YAFFS_COMMON_SOURCES="\
yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h \
yaffs_tagscompat.c yaffs_tagscompat.h \
+ yaffs_tagsmarshall.c yaffs_tagsmarshall.h \
yaffs_packedtags1.c yaffs_packedtags1.h \
yaffs_packedtags2.c yaffs_packedtags2.h \
yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.h \
if [ "$1" = "copy" ] ; then
+set -e -x
for i in $YAFFS_COMMON_SOURCES ; do
sed ../$i \
-e "s/strcat/yaffs_strcat/g" \
+++ /dev/null
-# Makefile for YAFFS direct stress tests
-#
-#
-# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
-#
-# Copyright (C) 2003-2010 Aleph One Ltd.
-#
-#
-# Created by Charles Manning <charles@aleph1.co.uk>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation.
-#
-# NB Warning this Makefile does not include header dependencies.
-#
-# $Id: Makefile,v 1.6 2010-02-17 00:51:15 charles Exp $
-
-#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
-
-CFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_YAFFS2 -DCONFIG_YAFFS_DEFINES_TYPES
-CFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES -DNO_Y_INLINE
-CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS) -Wstrict-aliasing
-#CFLAGS += -fno-strict-aliasing
-CFLAGS += -O0 -fPIC
-#CFLAGS += -DVALGRIND_TEST
-
-#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
-#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
-
-
-COMMONTESTOBJS = yaffscfg2k.o yaffs_osglue.o yaffs_hweight.o\
- yramsim.o yaffs_fileem2k.o\
- yaffs_nandif.o yaffs_attribs.o \
- yaffsfs.o yaffs_ecc.o yaffs_guts.o \
- yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
- yaffs_tagscompat.o yaffs_packedtags2.o yaffs_nand.o \
- yaffs_checkptrw.o yaffs_qsort.o\
- yaffs_nameval.o \
- yaffs_summary.o \
- yaffs_allocator.o \
- yaffs_norif1.o ynorsim.o \
- yaffs_bitmap.o \
- yaffs_verify.o \
- yaffs_yaffs1.o yaffs_yaffs2.o \
- yaffs_error.o
-
-
-YAFFSLIBOBJS = $(COMMONTESTOBJS) yaffs_python_helper.o
-
-
-
-
-
-YAFFSDIRECTSYMLINKS = \
- yaffsfs.c yaffsfs.h yaffscfg.h yaffs_osglue.h ydirectenv.h \
- yaffs_flashif.h yaffs_flashif2.h yaffs_list.h \
- yaffs_nandif.c yaffs_nandif.h yaffs_qsort.c yaffs_nandemul2k.h \
- yportenv.h yaffs_attribs.c \
- yaffs_hweight.c yaffs_hweight.h \
- yaffs_error.c \
- yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffs_tagscompat.c yaffs_tagscompat.h \
- yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h \
- yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.h \
- yaffs_checkptrw.h yaffs_checkptrw.c \
- yaffs_summary.c yaffs_summary.h \
- yaffs_nameval.c yaffs_nameval.h yaffs_attribs.h \
- yaffs_trace.h \
- yaffs_allocator.c yaffs_allocator.h \
- yaffs_yaffs1.c yaffs_yaffs1.h \
- yaffs_yaffs2.c yaffs_yaffs2.h \
- yaffs_bitmap.c yaffs_bitmap.h \
- yaffs_verify.c yaffs_verify.h
-
-DIRECTEXTRASYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffs_fileem2k.h\
- yaffs_fileem.c yaffs_norif1.c yaffs_norif1.h \
- yaffs_ramdisk.c yaffs_ramdisk.h yaffs_ramem2k.c \
- yaffsnewcfg.c yramsim.c yramsim.h \
- ynorsim.h ynorsim.c yaffs_osglue.c
-
-COPIED_SOURCES = $(YAFFSDIRECTSYMLINKS) $(DIRECTEXTRASYMLINKS)
-
-all: libyaffsfs.so
-
-
-$(YAFFSLIBOBJS): %.o: %.c
- gcc -c $(CFLAGS) -o $@ $<
-
-
-$(YAFFSDIRECTSYMLINKS):
- ln -s ../$@ $@
-
-$(DIRECTEXTRASYMLINKS):
- ln -s ../basic-test/$@ $@
-
-
-libyaffsfs.so: $(COPIED_SOURCES) $(YAFFSLIBOBJS)
- gcc -shared $(YAFFSLIBOBJS) -o $@
-
-
-clean:
- rm -f $(YAFFSLIBOBJS) core $(COPIED_SOURCES)
- rm -f libyaffsfs.so
- rm -f *.pyc
-# Makefile for YAFFS direct stress tests
+# Makefile rules for building in test framwork
#
#
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
#
# NB Warning this Makefile does not include header dependencies.
#
-# $Id: Makefile,v 1.7 2010-02-25 22:34:47 charles Exp $
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
CFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_YAFFS2 -DCONFIG_YAFFS_DEFINES_TYPES
CFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES
-CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS) -Wstrict-aliasing
+CFLAGS += -Wall -g $(EXTRA_COMPILE_FLAGS) -Wstrict-aliasing
#CFLAGS += -fno-strict-aliasing
CFLAGS += -O0
CFLAGS += -Wextra -Wpointer-arith
COMMONTESTOBJS = yaffscfg2k.o yaffs_osglue.o yaffs_hweight.o\
yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
- yaffs_tagscompat.o yaffs_packedtags2.o yaffs_nand.o \
+ yaffs_tagscompat.o yaffs_tagsmarshall.o \
+ yaffs_packedtags2.o yaffs_nand.o \
yaffs_checkptrw.o yaffs_qsort.o\
yaffs_nameval.o yaffs_attribs.o \
- yaffs_norif1.o ynorsim.o nor_stress.o yaffs_fsx.o \
+ yaffs_m18_drv.o ynorsim.o \
yaffs_allocator.o \
yaffs_bitmap.o \
yaffs_yaffs1.o \
yaffs_verify.o \
yaffs_summary.o
-# yaffs_checkptrwtest.o\
-YAFFSTESTOBJS = $(COMMONTESTOBJS) yaffs_test.o
-
-ALLOBJS = $(sort $(YAFFSTESTOBJS))
+ALLOBJS = $(sort $(ALL_UNSORTED_OBJS))
YAFFSDIRECTSYMLINKS = \
yaffsfs.c yaffs_flashif.h yaffs_flashif2.h\
yaffs_hweight.c yaffs_hweight.h \
yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h \
yaffs_tagscompat.c yaffs_tagscompat.h \
+ yaffs_tagsmarshall.c yaffs_tagsmarshall.h \
yaffs_packedtags1.c yaffs_packedtags1.h \
yaffs_packedtags2.c yaffs_packedtags2.h \
yaffs_nand.c yaffs_nand.h yaffs_getblockinfo.h \
yaffs_summary.c yaffs_summary.h
-DIRECTEXTRASYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffs_fileem2k.h\
- yaffs_fileem.c yaffs_norif1.c yaffs_norif1.h \
- yaffs_ramdisk.c yaffs_ramdisk.h yaffs_ramem2k.c \
- ynorsim.h ynorsim.c yaffs_osglue.c
-
-COPIED_SOURCES = $(YAFFSDIRECTSYMLINKS) $(DIRECTEXTRASYMLINKS)
+FRAMEWORKEXTRASYMLINKS = \
+ yaffscfg2k.c yaffs_fileem2k.c yaffs_fileem2k.h\
+ yaffs_fileem.c yaffs_m18_drv.c yaffs_m18_drv.h \
+ yaffs_ramdisk.c yaffs_ramdisk.h yaffs_ramem2k.c \
+ ynorsim.h ynorsim.c yaffs_osglue.c
-all: yaffs_test fuzzer
-
-$(ALLOBJS): %.o: %.c
- gcc -c $(CFLAGS) -o $@ $<
+FRAMEWORK_SOURCES = $(YAFFSDIRECTSYMLINKS) $(FRAMEWORKEXTRASYMLINKS)
+clean:
+ rm -f $(TARGETS) $(ALLOBJS) core $(FRAMEWORK_SOURCES)
$(YAFFSDIRECTSYMLINKS):
- ln -s ../$@ $@
+ ln -s $(YDI_DIR)/$@ $@
-$(DIRECTEXTRASYMLINKS):
- ln -s ../basic-test/$@ $@
+$(FRAMEWORKEXTRASYMLINKS):
+ ln -s $(YDI_FRAMEWORK_DIR)/$@ $@
-yaffs_test: $(COPIED_SOURCES) $(YAFFSTESTOBJS)
- gcc $(CFLLAG) -o $@ $(YAFFSTESTOBJS)
-
-fuzzer: fuzzer.c
- gcc $(CFLAGS) -o $@ $<
-
-clean:
- rm -f yaffs_test fuzzer fuzzer.o $(ALLOBJS) core $(COPIED_SOURCES)
+$(ALLOBJS): %.o: %.c
+ gcc -c $(CFLAGS) -o $@ $<
--- /dev/null
+# Makefile for YAFFS direct test
+#
+#
+# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
+#
+# Copyright (C) 2003-2010 Aleph One Ltd.
+#
+#
+# Created by Charles Manning <charles@aleph1.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# NB Warning this Makefile does not include header dependencies.
+#
+
+
+
+
+YDI_DIR = ../../
+YDI_FRAMEWORK_DIR = ../
+
+TARGETS = directtest2k
+
+all: $(TARGETS)
+
+DIRECTTESTOBJS = $(COMMONTESTOBJS) dtest.o
+
+ALL_UNSORTED_OBJS += $(DIRECTTESTOBJS)
+
+include ../FrameworkRules.mk
+
+directtest2k: $(FRAMEWORK_SOURCES) $(DIRECTTESTOBJS)
+ gcc -o $@ $(DIRECTTESTOBJS)
+
--- /dev/null
+# Makefile for YAFFS direct stress tests
+#
+#
+# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
+#
+# Copyright (C) 2003-2010 Aleph One Ltd.
+#
+#
+# Created by Charles Manning <charles@aleph1.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# NB Warning this Makefile does not include header dependencies.
+#
+
+
+
+
+
+
+
+$(YAFFSLIBOBJS): %.o: %.c
+ gcc -c $(CFLAGS) -o $@ $<
+
+
+$(YAFFSDIRECTSYMLINKS):
+ ln -s ../$@ $@
+
+$(DIRECTEXTRASYMLINKS):
+ ln -s ../basic-test/$@ $@
+
+
+# Makefile for stress tests and fuzzer
+#
+#
+# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
+#
+# Copyright (C) 2003-2010 Aleph One Ltd.
+#
+#
+# Created by Charles Manning <charles@aleph1.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# NB Warning this Makefile does not include header dependencies.
+#
+
+YDI_DIR = ../../
+YDI_FRAMEWORK_DIR = ../
+
+TARGETS = libyaffsfs.so
+
+
+all: $(TARGETS)
+
+
+YAFFSLIBOBJS = $(COMMONTESTOBJS) yaffs_python_helper.o
+
+ALL_UNSORTED_OBJS += $(YAFFSLIBOBJS)
+
+include ../FrameworkRules.mk
+
+CFLAGS += -O0 -fPIC
+
+
+libyaffsfs.so: $(FRAMEWORK_SOURCES) $(YAFFSLIBOBJS)
+ gcc -shared $(YAFFSLIBOBJS) -o $@
+
--- /dev/null
+# Makefile for stress tests and fuzzer
+#
+#
+# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
+#
+# Copyright (C) 2003-2010 Aleph One Ltd.
+#
+#
+# Created by Charles Manning <charles@aleph1.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# NB Warning this Makefile does not include header dependencies.
+#
+
+YDI_DIR = ../../
+YDI_FRAMEWORK_DIR = ../
+
+TARGETS = yaffs_test fuzzer
+
+all: $(TARGETS)
+
+YAFFS_TEST_OBJS = $(COMMONTESTOBJS) yaffs_test.o nor_stress.o yaffs_fsx.o
+FUZZER_OBJS = fuzzer.o
+
+ALL_UNSORTED_OBJS += $(YAFFS_TEST_OBJS) $(FUZZER_OBJS)
+
+include ../FrameworkRules.mk
+
+
+yaffs_test: $(FRAMEWORK_SOURCES) $(YAFFS_TEST_OBJS)
+ gcc $(CFLLAG) -o $@ $(YAFFS_TEST_OBJS)
+
+fuzzer: $(FUZZER_OBJS)
+ gcc $(CFLAGS) -o $@ $<
* This is only intended as test code to test persistence etc.
*/
-const char *yaffs_flashif_c_version = "$Id: yaffs_fileem.c,v 1.7 2010-02-18 01:18:04 charles Exp $";
-
-
#include "yportenv.h"
#include "yaffs_trace.h"
--- /dev/null
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This provides a YAFFS nand emulation on a file for emulating 2kB pages.
+ * This is only intended as test code to test persistence etc.
+ */
+
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+#include "yaffs_flashif2.h"
+#include "yaffs_guts.h"
+#include "yaffs_fileem2k.h"
+#include "yaffs_packedtags2.h"
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#if 1
+
+#define SIZE_IN_MB 32
+/* #define SIZE_IN_MB 128 */
+
+#define PAGE_DATA_SIZE (2048)
+#define PAGE_SPARE_SIZE (64)
+#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
+#define PAGES_PER_BLOCK (64)
+#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK)
+#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE))
+#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE)
+#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB)
+
+#else
+
+#define SIZE_IN_MB 128
+#define PAGE_DATA_SIZE (512)
+#define SPARE_SIZE (16)
+#define PAGE_SIZE (PAGE_DATA_SIZE + SPARE_SIZE)
+#define PAGES_PER_BLOCK (32)
+#define BLOCK_DATA_SIZE (PAGE_SIZE * PAGES_PER_BLOCK)
+#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE))
+#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE)
+#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB)
+
+#endif
+
+#define REPORT_ERROR 0
+
+typedef struct
+{
+ u8 data[PAGE_SIZE]; // Data + spare
+} yflash_Page;
+
+typedef struct
+{
+ yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
+
+} yflash_Block;
+
+
+
+#define MAX_HANDLES 20
+#define BLOCKS_PER_HANDLE (32*8)
+
+typedef struct
+{
+ int handle[MAX_HANDLES];
+ int nBlocks;
+} yflash_Device;
+
+static yflash_Device filedisk;
+
+int yaffs_test_partial_write = 0;
+
+extern int random_seed;
+extern int simulate_power_failure;
+static int remaining_ops;
+static int nops_so_far;
+
+int ops_multiplier;
+
+
+static void yflash2_MaybePowerFail(unsigned int nand_chunk, int failPoint)
+{
+
+ nops_so_far++;
+
+
+ remaining_ops--;
+ if(simulate_power_failure &&
+ remaining_ops < 1){
+ printf("Simulated power failure after %d operations\n",nops_so_far);
+ printf(" power failed on nand_chunk %d, at fail point %d\n",
+ nand_chunk, failPoint);
+ exit(0);
+ }
+}
+
+
+
+
+
+static u8 localBuffer[PAGE_SIZE];
+
+static char *NToName(char *buf,int n)
+{
+ sprintf(buf,"emfile-2k-%d",n);
+ return buf;
+}
+
+static char dummyBuffer[BLOCK_SIZE];
+
+static int GetBlockFileHandle(int n)
+{
+ int h;
+ int requiredSize;
+
+ char name[40];
+ NToName(name,n);
+ int fSize;
+ int i;
+
+ h = open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
+ if(h >= 0){
+ fSize = lseek(h,0,SEEK_END);
+ requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
+ if(fSize < requiredSize){
+ for(i = 0; i < BLOCKS_PER_HANDLE; i++)
+ if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
+ return -1;
+
+ }
+ }
+
+ return h;
+
+}
+
+static int CheckInit(void)
+{
+ static int initialised = 0;
+ int i;
+
+ int blk;
+
+
+ if(initialised)
+ {
+ return YAFFS_OK;
+ }
+
+ initialised = 1;
+
+
+ srand(random_seed);
+ remaining_ops = (rand() % 1000) * 5;
+ memset(dummyBuffer,0xff,sizeof(dummyBuffer));
+
+
+
+ filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
+
+ for(i = 0; i < MAX_HANDLES; i++)
+ filedisk.handle[i] = -1;
+
+ for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
+ filedisk.handle[i] = GetBlockFileHandle(i);
+
+
+ return 1;
+}
+
+
+int yflash2_GetNumberOfBlocks(void)
+{
+ CheckInit();
+
+ return filedisk.nBlocks;
+}
+
+
+int yaffs_check_all_ff(const u8 *ptr, int n)
+{
+ while(n)
+ {
+ n--;
+ if(*ptr!=0xFF) return 0;
+ ptr++;
+ }
+ return 1;
+}
+
+
+static int yflash2_WriteChunk(struct yaffs_dev *dev, int nand_chunk,
+ const u8 *data, int data_len,
+ const u8 *oob, int oob_len)
+{
+ int retval = YAFFS_OK;
+ int pos;
+ int h;
+ int nwritten;
+
+ (void) dev;
+
+ if (data && data_len) {
+ pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
+ h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
+ lseek(h,pos,SEEK_SET);
+ nwritten = write(h,data,data_len);
+ if(nwritten != data_len)
+ retval = YAFFS_FAIL;
+ }
+
+ if (oob && oob_len) {
+ pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
+ h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
+ lseek(h,pos,SEEK_SET);
+ nwritten = write(h,oob,oob_len);
+ if(nwritten != oob_len)
+ retval = YAFFS_FAIL;
+ }
+
+ yflash2_MaybePowerFail(nand_chunk,3);
+
+ return retval;
+}
+
+static int yflash2_ReadChunk(struct yaffs_dev *dev, int nand_chunk,
+ u8 *data, int data_len,
+ u8 *oob, int oob_len,
+ enum yaffs_ecc_result *ecc_result)
+{
+ int retval = YAFFS_OK;
+ int pos;
+ int h;
+ int nread;
+
+ (void) dev;
+
+ if (data && data_len) {
+ pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
+ h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
+ lseek(h,pos,SEEK_SET);
+ nread = read(h,data,data_len);
+ if(nread != data_len)
+ retval = YAFFS_FAIL;
+ }
+
+ if (oob && oob_len) {
+ pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
+ h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
+ lseek(h,pos,SEEK_SET);
+ nread = read(h,oob,oob_len);
+ if(nread != oob_len)
+ retval = YAFFS_FAIL;
+ }
+
+ if (ecc_result)
+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+ return retval;
+}
+
+static int yflash2_EraseBlock(struct yaffs_dev *dev, int block_no)
+{
+ int i;
+ int h;
+
+ CheckInit();
+
+ if(block_no < 0 || block_no >= filedisk.nBlocks)
+ {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,"Attempt to erase non-existant block %d",block_no);
+ return YAFFS_FAIL;
+ }
+ else
+ {
+
+ u8 pg[PAGE_SIZE];
+ int syz = PAGE_SIZE;
+ int pos;
+
+ memset(pg,0xff,syz);
+
+
+ h = filedisk.handle[(block_no / ( BLOCKS_PER_HANDLE))];
+ lseek(h,((block_no % BLOCKS_PER_HANDLE) * dev->param.chunks_per_block) * PAGE_SIZE,SEEK_SET);
+ for(i = 0; i < dev->param.chunks_per_block; i++)
+ {
+ write(h,pg,PAGE_SIZE);
+ }
+ pos = lseek(h, 0,SEEK_CUR);
+
+ return YAFFS_OK;
+ }
+}
+
+static int yflash2_MarkBad(struct yaffs_dev *dev, int block_no)
+{
+ int written;
+ int h;
+
+ struct yaffs_packed_tags2 pt;
+
+ CheckInit();
+
+ memset(&pt,0,sizeof(pt));
+ h = filedisk.handle[(block_no / ( BLOCKS_PER_HANDLE))];
+ lseek(h,((block_no % BLOCKS_PER_HANDLE) * dev->param.chunks_per_block) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
+ written = write(h,&pt,sizeof(pt));
+
+ if(written != sizeof(pt))
+ return YAFFS_FAIL;
+
+ return YAFFS_OK;
+
+}
+
+static int yflash2_CheckBad(struct yaffs_dev *dev, int block_no)
+{
+ (void) dev;
+ (void) block_no;
+
+ return YAFFS_OK;
+}
+
+static int yflash2_Initialise(struct yaffs_dev *dev)
+{
+ (void) dev;
+
+ CheckInit();
+
+ return YAFFS_OK;
+}
+
+struct yaffs_dev *yflash2_install_drv(const char *name)
+{
+ struct yaffs_dev *dev = NULL;
+ struct yaffs_param *param;
+ struct yaffs_driver *drv;
+
+ dev = malloc(sizeof(*dev));
+
+ if(!dev)
+ return NULL;
+
+ memset(dev, 0, sizeof(*dev));
+
+ dev->param.name = strdup(name);
+
+ if(!dev->param.name) {
+ free(dev);
+ return NULL;
+ }
+
+ drv = &dev->drv;
+
+ drv->drv_write_chunk_fn = yflash2_WriteChunk;
+ drv->drv_read_chunk_fn = yflash2_ReadChunk;
+ drv->drv_erase_fn = yflash2_EraseBlock;
+ drv->drv_mark_bad_fn = yflash2_MarkBad;
+ drv->drv_check_bad_fn = yflash2_CheckBad;
+ drv->drv_initialise_fn = yflash2_Initialise;
+
+ param = &dev->param;
+
+ param->total_bytes_per_chunk = 2048;
+ param->chunks_per_block = 64;
+ param->start_block = 0;
+ param->end_block = yflash2_GetNumberOfBlocks()-1;
+ param->is_yaffs2 = 1;
+ param->use_nand_ecc=1;
+
+ param->n_reserved_blocks = 5;
+ param->wide_tnodes_disabled=0;
+ param->refresh_period = 1000;
+ param->n_caches = 10; // Use caches
+
+ param->enable_xattr = 1;
+
+ /* dev->driver_context is not used by this simulator */
+
+ yaffs_add_device(dev);
+
+ return dev;
+}
--- /dev/null
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __FILEEM2K_H__
+#define __FILEEM2K_H__
+
+
+struct yaffs_dev;
+
+struct yaffs_dev *yflash2_install_drv(const char *name);
+
+
+#endif
+
/* First set up for M18 with 1k chunks and 16-byte spares.
*
- * NB We're using the oddball M18 modes of operation here
+ * NB We're using the oddball M18 modes of operation here
* The chip is 64MB based at 0x0000, but YAFFS only going to use the top half
* ie. YAFFS will be from 32MB to 64MB.
*
- * The M18 has two ways of writing data. Every Programming Region (1kbytes)
+ * The M18 has two ways of writing data. Every Programming Region (1kbytes)
* can be programmed in two modes:
* * Object Mode 1024 bytes of write once data.
- * * Control Mode: 512bytes of bit-writeable data.
+ * * Control Mode: 512bytes of bit-writeable data.
* This is arranged as 32 * (16 bytes of bit-writable followed by 16 bytes of "dont touch")
- *
+ *
* The block size is 256kB, making 128 blocks in the 32MB YAFFS area.
* Each block comprises:
* Offset 0k: 248 x 1k data pages
* Offset 248k: 248 x 32-byte spare areas implemented as 16 bytes of spare followed by 16 bytes untouched)
* Offset 248k + (248 * 32): Format marker
- *
+ *
*/
-const char *yaffs_norif1_c_version = "$Id: yaffs_norif1.c,v 1.6 2010-02-18 01:18:04 charles Exp $";
-
-#include "yaffs_norif1.h"
+#include "yaffs_m18_drv.h"
#include "yportenv.h"
#include "yaffs_trace.h"
#define CHUNKS_PER_BLOCK 248
#define SPARE_AREA_OFFSET (CHUNKS_PER_BLOCK * PROG_REGION_SIZE)
-#define FORMAT_OFFSET (SPARE_AREA_OFFSET + CHUNKS_PER_BLOCK * (SPARE_BYTES_PER_CHUNK + M18_SKIP))
+#define FORMAT_OFFSET (SPARE_AREA_OFFSET + CHUNKS_PER_BLOCK * \
+ (SPARE_BYTES_PER_CHUNK + M18_SKIP))
#define FORMAT_VALUE 0x1234
/* Compile this for a simulation */
#include "ynorsim.h"
-#define ynorif1_FlashInit() ynorsim_initialise()
-#define ynorif1_FlashDeinit() ynorsim_shutdown()
-#define ynorif1_FlashWrite32(addr,buf,nwords) ynorsim_wr32(addr,buf,nwords)
-#define ynorif1_FlashRead32(addr,buf,nwords) ynorsim_rd32(addr,buf,nwords)
-#define ynorif1_FlashEraseBlock(addr) ynorsim_erase(addr)
+#define m18_drv_FlashInit() ynorsim_initialise()
+#define m18_drv_FlashDeinit() ynorsim_shutdown()
+#define m18_drv_FlashWrite32(addr,buf,nwords) ynorsim_wr32(addr,buf,nwords)
+#define m18_drv_FlashRead32(addr,buf,nwords) ynorsim_rd32(addr,buf,nwords)
+#define m18_drv_FlashEraseBlock(addr) ynorsim_erase(addr)
#define DEVICE_BASE ynorsim_get_base()
#else
-/* Compile this for running on blob, hacked for yaffs access */
+/* Compile this to hook up to read hardware */
#include "../blob/yflashrw.h"
-#define ynorif1_FlashInit() do{} while(0)
-#define ynorif1_FlashDeinit() do {} while(0)
-#define ynorif1_FlashWrite32(addr,buf,nwords) Y_FlashWrite(addr,buf,nwords)
-#define ynorif1_FlashRead32(addr,buf,nwords) Y_FlashRead(addr,buf,nwords)
-#define ynorif1_FlashEraseBlock(addr) Y_FlashErase(addr,BLOCK_SIZE_IN_BYTES)
+#define m18_drv_FlashInit() do{} while(0)
+#define m18_drv_FlashDeinit() do {} while(0)
+#define m18_drv_FlashWrite32(addr,buf,nwords) Y_FlashWrite(addr,buf,nwords)
+#define m18_drv_FlashRead32(addr,buf,nwords) Y_FlashRead(addr,buf,nwords)
+#define m18_drv_FlashEraseBlock(addr) Y_FlashErase(addr,BLOCK_SIZE_IN_BYTES)
#define DEVICE_BASE (32 * 1024 * 1024)
#endif
-u32 *Block2Addr(struct yaffs_dev *dev, int blockNumber)
+static u32 *Block2Addr(struct yaffs_dev *dev, int blockNumber)
{
u32 addr;
dev=dev;
-
+
addr = (u32) DEVICE_BASE;
addr += blockNumber * BLOCK_SIZE_IN_BYTES;
-
+
return (u32 *) addr;
}
-u32 *Block2FormatAddr(struct yaffs_dev *dev,int blockNumber)
+static u32 *Block2FormatAddr(struct yaffs_dev *dev,int blockNumber)
{
u32 addr;
addr = (u32) Block2Addr(dev,blockNumber);
addr += FORMAT_OFFSET;
-
+
return (u32 *)addr;
}
-u32 *Chunk2DataAddr(struct yaffs_dev *dev,int chunk_id)
+
+static u32 *Chunk2DataAddr(struct yaffs_dev *dev,int chunk_id)
{
unsigned block;
unsigned chunkInBlock;
u32 addr;
-
+
block = chunk_id/dev->param.chunks_per_block;
chunkInBlock = chunk_id % dev->param.chunks_per_block;
-
+
addr = (u32) Block2Addr(dev,block);
addr += chunkInBlock * DATA_BYTES_PER_CHUNK;
-
+
return (u32 *)addr;
}
-u32 *Chunk2SpareAddr(struct yaffs_dev *dev,int chunk_id)
+static u32 *Chunk2SpareAddr(struct yaffs_dev *dev,int chunk_id)
{
unsigned block;
unsigned chunkInBlock;
u32 addr;
-
+
block = chunk_id/dev->param.chunks_per_block;
chunkInBlock = chunk_id % dev->param.chunks_per_block;
-
+
addr = (u32) Block2Addr(dev,block);
addr += SPARE_AREA_OFFSET;
addr += chunkInBlock * (SPARE_BYTES_PER_CHUNK + M18_SKIP);
}
-void ynorif1_AndBytes(u8*target, const u8 *src, int nbytes)
+static void m18_drv_AndBytes(u8*target, const u8 *src, int nbytes)
{
while(nbytes > 0){
*target &= *src;
}
}
-int ynorif1_WriteChunkToNAND(struct yaffs_dev *dev,int nand_chunk,const u8 *data, const struct yaffs_spare *spare)
+static int m18_drv_WriteChunkToNAND(struct yaffs_dev *dev,int nand_chunk,
+ const u8 *data, int data_len,
+ const u8 *oob, int oob_len)
{
u32 *dataAddr = Chunk2DataAddr(dev,nand_chunk);
u32 *spareAddr = Chunk2SpareAddr(dev,nand_chunk);
-
+
+ struct yaffs_spare *spare = (struct yaffs_spare *)oob;
struct yaffs_spare tmpSpare;
-
+
+ (void) oob_len;
+
/* We should only be getting called for one of 3 reasons:
* Writing a chunk: data and spare will not be NULL
* Writing a deletion marker: data will be NULL, spare not NULL
* Writing a bad block marker: data will be NULL, spare not NULL
*/
-
+
if(sizeof(struct yaffs_spare) != 16)
BUG();
-
- if(data && spare)
+
+ if(data && oob)
{
if(spare->page_status != 0xff)
BUG();
/* Write a pre-marker */
memset(&tmpSpare,0xff,sizeof(tmpSpare));
tmpSpare.page_status = YNOR_PREMARKER;
- ynorif1_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(struct yaffs_spare)/4);
+ m18_drv_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(struct yaffs_spare)/4);
+
+ /* Write the data */
+ m18_drv_FlashWrite32(dataAddr,(u32 *)data, data_len/ 4);
+
- /* Write the data */
- ynorif1_FlashWrite32(dataAddr,(u32 *)data,dev->param.total_bytes_per_chunk / 4);
-
-
memcpy(&tmpSpare,spare,sizeof(struct yaffs_spare));
-
+
/* Write the real tags, but override the premarker*/
tmpSpare.page_status = YNOR_PREMARKER;
- ynorif1_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(struct yaffs_spare)/4);
-
+ m18_drv_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(struct yaffs_spare)/4);
+
/* Write a post-marker */
tmpSpare.page_status = YNOR_POSTMARKER;
- ynorif1_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(tmpSpare)/4);
+ m18_drv_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(tmpSpare)/4);
} else if(spare){
/* This has to be a read-modify-write operation to handle NOR-ness */
- ynorif1_FlashRead32(spareAddr,(u32 *)&tmpSpare,16/ 4);
-
- ynorif1_AndBytes((u8 *)&tmpSpare,(u8 *)spare,sizeof(struct yaffs_spare));
-
- ynorif1_FlashWrite32(spareAddr,(u32 *)&tmpSpare,16/ 4);
+ m18_drv_FlashRead32(spareAddr,(u32 *)&tmpSpare,16/ 4);
+
+ m18_drv_AndBytes((u8 *)&tmpSpare,(u8 *)spare,sizeof(struct yaffs_spare));
+
+ m18_drv_FlashWrite32(spareAddr,(u32 *)&tmpSpare,16/ 4);
}
else {
BUG();
}
-
- return YAFFS_OK;
+
+ return YAFFS_OK;
}
-int ynorif1_ReadChunkFromNAND(struct yaffs_dev *dev,int nand_chunk, u8 *data, struct yaffs_spare *spare)
+static int m18_drv_ReadChunkFromNAND(struct yaffs_dev *dev,int nand_chunk,
+ u8 *data, int data_len,
+ u8 *oob, int oob_len,
+ enum yaffs_ecc_result *ecc_result)
{
+ struct yaffs_spare *spare = (struct yaffs_spare *)oob;
u32 *dataAddr = Chunk2DataAddr(dev,nand_chunk);
u32 *spareAddr = Chunk2SpareAddr(dev,nand_chunk);
-
+
if(data)
{
- ynorif1_FlashRead32(dataAddr,(u32 *)data,dev->param.total_bytes_per_chunk / 4);
+ m18_drv_FlashRead32(dataAddr,(u32 *)data,dev->param.total_bytes_per_chunk / 4);
}
-
- if(spare)
+
+ if(oob)
{
- ynorif1_FlashRead32(spareAddr,(u32 *)spare,16/ 4);
-
+ m18_drv_FlashRead32(spareAddr,(u32 *)spare, oob_len/ 4);
+
/* If the page status is YNOR_POSTMARKER then it was written properly
* so change that to 0xFF so that the rest of yaffs is happy.
*/
(spare->page_status | YNOR_PREMARKER) != 0xff)
spare->page_status = YNOR_PREMARKER;
}
-
- return YAFFS_OK;
+ if(ecc_result)
+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+ return YAFFS_OK;
}
-static int ynorif1_FormatBlock(struct yaffs_dev *dev, int blockNumber)
+
+static int m18_drv_FormatBlock(struct yaffs_dev *dev, int blockNumber)
{
u32 *blockAddr = Block2Addr(dev,blockNumber);
u32 *formatAddr = Block2FormatAddr(dev,blockNumber);
u32 formatValue = FORMAT_VALUE;
-
- ynorif1_FlashEraseBlock(blockAddr);
- ynorif1_FlashWrite32(formatAddr,&formatValue,1);
-
+
+ m18_drv_FlashEraseBlock(blockAddr);
+ m18_drv_FlashWrite32(formatAddr,&formatValue,1);
+
return YAFFS_OK;
}
-static int ynorif1_UnformatBlock(struct yaffs_dev *dev, int blockNumber)
+static int m18_drv_UnformatBlock(struct yaffs_dev *dev, int blockNumber)
{
u32 *formatAddr = Block2FormatAddr(dev,blockNumber);
u32 formatValue = 0;
-
- ynorif1_FlashWrite32(formatAddr,&formatValue,1);
-
+
+ m18_drv_FlashWrite32(formatAddr,&formatValue,1);
+
return YAFFS_OK;
}
-static int ynorif1_IsBlockFormatted(struct yaffs_dev *dev, int blockNumber)
+static int m18_drv_IsBlockFormatted(struct yaffs_dev *dev, int blockNumber)
{
u32 *formatAddr = Block2FormatAddr(dev,blockNumber);
u32 formatValue;
-
-
- ynorif1_FlashRead32(formatAddr,&formatValue,1);
-
+
+
+ m18_drv_FlashRead32(formatAddr,&formatValue,1);
+
return (formatValue == FORMAT_VALUE);
}
-int ynorif1_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
+static int m18_drv_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
{
if(blockNumber < 0 || blockNumber >= BLOCKS_IN_DEVICE)
}
else
{
- ynorif1_UnformatBlock(dev,blockNumber);
- ynorif1_FormatBlock(dev,blockNumber);
+ m18_drv_UnformatBlock(dev,blockNumber);
+ m18_drv_FormatBlock(dev,blockNumber);
return YAFFS_OK;
}
-
+
}
-int ynorif1_InitialiseNAND(struct yaffs_dev *dev)
+static int m18_drv_InitialiseNAND(struct yaffs_dev *dev)
{
int i;
-
- ynorif1_FlashInit();
+
+ m18_drv_FlashInit();
/* Go through the blocks formatting them if they are not formatted */
for(i = dev->param.start_block; i <= dev->param.end_block; i++){
- if(!ynorif1_IsBlockFormatted(dev,i)){
- ynorif1_FormatBlock(dev,i);
+ if(!m18_drv_IsBlockFormatted(dev,i)){
+ m18_drv_FormatBlock(dev,i);
}
}
return YAFFS_OK;
}
-int ynorif1_Deinitialise_flash_fn(struct yaffs_dev *dev)
+static int m18_drv_Deinitialise_flash_fn(struct yaffs_dev *dev)
{
- dev=dev;
- ynorif1_FlashDeinit();
+ dev=dev;
+ m18_drv_FlashDeinit();
return YAFFS_OK;
}
+struct yaffs_dev *yaffs_m18_install_drv(const char *name)
+{
+
+ struct yaffs_dev *dev = malloc(sizeof(struct yaffs_dev));
+ char *name_copy = strdup(name);
+ struct yaffs_param *param;
+ struct yaffs_driver *drv;
+
+
+ if(!dev || !name_copy) {
+ free(name_copy);
+ free(dev);
+ return NULL;
+ }
+
+ param = &dev->param;
+ drv = &dev->drv;
+
+ memset(dev, 0, sizeof(*dev));
+
+ param->name = name_copy;
+
+ param->total_bytes_per_chunk = 1024;
+ param->chunks_per_block =248;
+ param->n_reserved_blocks = 2;
+ param->start_block = 0; // Can use block 0
+ param->end_block = 31; // Last block
+ param->use_nand_ecc = 0; // use YAFFS's ECC
+
+ drv->drv_write_chunk_fn = m18_drv_WriteChunkToNAND;
+ drv->drv_read_chunk_fn = m18_drv_ReadChunkFromNAND;
+ drv->drv_erase_fn = m18_drv_EraseBlockInNAND;
+ drv->drv_initialise_fn = m18_drv_InitialiseNAND;
+ drv->drv_deinitialise_fn = m18_drv_Deinitialise_flash_fn;
+
+ param->n_caches = 10;
+ param->disable_soft_del = 1;
+
+ dev->driver_context = (void *) 1; // Used to identify the device in fstat.
+
+ yaffs_add_device(dev);
+
+ return NULL;
+}
--- /dev/null
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YAFFS_M18_DRV_H__
+#define __YAFFS_M18_DRV_H__
+
+struct yaffs_dev;
+struct yaffs_dev *yaffs_m18_install_drv(const char *name);
+
+#endif
+
+
#include "yaffscfg.h"
#include "yaffs_guts.h"
#include "yaffsfs.h"
-#include "yaffs_fileem2k.h"
-#include "yaffs_nandemul2k.h"
-#include "yaffs_norif1.h"
#include "yaffs_trace.h"
#include <assert.h>
return yaffsfs_lastError;
}
+int yaffsfs_CheckMemRegion(const void *addr, size_t size, int writeable)
+{
+ if(!addr)
+ return -1;
+ return 0;
+}
+
#ifdef CONFIG_YAFFS_USE_PTHREADS
#include <pthread.h>
* Use this with dev->use_nand_ecc enabled, then ECC overheads are not required.
*/
-const char *yaffs_ramdisk_c_version = "$Id: yaffs_ramdisk.c,v 1.6 2010-01-11 04:06:47 charles Exp $";
-
-
#include "yportenv.h"
#include "yaffs_trace.h"
*/
-const char *yaffs_ramem2k_c_version = "$Id: yaffs_ramem2k.c,v 1.8 2010-02-18 01:18:04 charles Exp $";
-
#ifndef __KERNEL__
#define CONFIG_YAFFS_RAM_ENABLED
#else
--- /dev/null
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * yaffscfg2k.c The configuration for the "direct" use of yaffs.
+ *
+ * This file is intended to be modified to your requirements.
+ * There is no need to redistribute this file.
+ */
+
+#include "yaffscfg.h"
+#include "yaffs_guts.h"
+#include "yaffsfs.h"
+#include "yaffs_fileem2k.h"
+#include "yaffs_nandemul2k.h"
+#include "yaffs_trace.h"
+#include "yaffs_osglue.h"
+
+
+#include <errno.h>
+
+unsigned yaffs_trace_mask =
+
+ YAFFS_TRACE_SCAN |
+ YAFFS_TRACE_GC |
+ YAFFS_TRACE_ERASE |
+ YAFFS_TRACE_ERROR |
+ YAFFS_TRACE_TRACING |
+ YAFFS_TRACE_ALLOCATE |
+ YAFFS_TRACE_BAD_BLOCKS |
+ YAFFS_TRACE_VERIFY |
+
+ 0;
+
+
+
+// Configuration
+
+#include "yaffs_flashif2.h"
+#include "yaffs_m18_drv.h"
+
+int yaffs_start_up(void)
+{
+ static int start_up_called = 0;
+
+ if(start_up_called)
+ return 0;
+ start_up_called = 1;
+
+ // Stuff to configure YAFFS
+ // Stuff to initialise anything special (eg lock semaphore).
+ yaffsfs_OSInitialisation();
+
+
+ yaffs_m18_install_drv("M18-1");
+
+ // /yaffs2 yaffs2 file emulation
+ yflash2_install_drv("yaffs2");
+
+ return 0;
+}
+
+
+
{test_yaffs_write,test_yaffs_write_clean,"test_yaffs_write"},
{test_yaffs_write_EBADF,test_yaffs_write_EBADF_clean,"test_yaffs_write_EBADF"},
- {test_yaffs_write_big_file,test_yaffs_write_big_file_clean,"test_yaffs_write_big_file"},
+// {test_yaffs_write_big_file,test_yaffs_write_big_file_clean,"test_yaffs_write_big_file"},
{test_yaffs_write_EROFS,test_yaffs_write_EROFS_clean,"test_yaffs_write_EROFS"},
{test_yaffs_read,test_yaffs_read_clean,"test_yaffs_read"},
void *yaffsfs_malloc(size_t size);
void yaffsfs_free(void *ptr);
+int yaffsfs_CheckMemRegion(const void *addr, size_t size, int writeable);
+
void yaffsfs_OSInitialisation(void);
thisMatchLength = 0;
matching = 1;
+ if(!p)
+ continue;
+
while (matching && *p && *leftOver) {
/* Skip over any /s */
while (yaffsfs_IsPathDivider(*p))
int notDir = 0;
int loop = 0;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0)< 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
Y_LOFF_T maxRead;
u8 *buf = (u8 *) vbuf;
- if (!vbuf) {
+ if (yaffsfs_CheckMemRegion(vbuf, nbyte, 1) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int nToWrite = 0;
const u8 *buf = (const u8 *)vbuf;
- if (!vbuf) {
+ if (yaffsfs_CheckMemRegion(vbuf, nbyte, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
YCHAR *alt_newpath = NULL;
- if (!oldPath || !newPath) {
+ if (yaffsfs_CheckMemRegion(oldPath, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(newPath, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!path || !buf) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(buf, sizeof(*buf), 1) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int retVal = -1;
- if (!buf) {
+ if (yaffsfs_CheckMemRegion(buf, sizeof(*buf), 1) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int retVal = -1;
- if (!path || !name || !data) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(name, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(data, size, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int retVal = -1;
- if (!name || !data) {
+ if (yaffsfs_CheckMemRegion(name, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(data, size, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!path || !name || !data) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(name, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(data, size, 1) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int retVal = -1;
- if (!name || !data) {
+ if (yaffsfs_CheckMemRegion(name, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(data, size, 1) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!path || !data) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(data, size, 1) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int retVal = -1;
- if (!data) {
+ if (yaffsfs_CheckMemRegion(data, size, 1) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int loop = 0;
int retVal = -1;
- if (!path || !name) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(name, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int retVal = -1;
- if (!name) {
+ if (yaffsfs_CheckMemRegion(name, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int loop = 0;
int retval = -1;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int result;
YCHAR *alt_path;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int result = YAFFS_FAIL;
struct yaffs_dev *dev = NULL;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
struct yaffs_dev *dev = NULL;
YCHAR *dummy;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int retVal = -1;
struct yaffs_dev *dev = NULL;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int retVal = -1;
struct yaffs_dev *dev = NULL;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
struct yaffs_dev *dev = NULL;
YCHAR *dummy;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
struct yaffs_dev *dev = NULL;
YCHAR *dummy;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
struct yaffs_dev *dev = NULL;
YCHAR *dummy;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!dirname) {
+ if (yaffsfs_CheckMemRegion(dirname, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return NULL;
}
dsc = (struct yaffsfs_DirSearchContxt *) dirp;
+ if (yaffsfs_CheckMemRegion(dirp, sizeof(*dsc), 0) < 0)
+ return;
+
yaffsfs_Lock();
yaffsfs_SetDirRewound(dsc);
dsc = (struct yaffsfs_DirSearchContxt *) dirp;
- if (!dsc) {
+ if (yaffsfs_CheckMemRegion(dirp, sizeof(*dsc), 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!oldpath || !newpath) {
+ if (yaffsfs_CheckMemRegion(oldpath, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(newpath, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int notDir = 0;
int loop = 0;
- if (!path || !buf) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(buf, bufsiz, 1) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
int lnkLoop = 0;
YCHAR *newname;
- if (!oldpath || !linkpath) {
+ if (yaffsfs_CheckMemRegion(oldpath, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(linkpath, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
{
struct yaffs_obj *obj;
- if (!path) {
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
return -1;
}
{
int i;
- if (!dev->param.erase_fn)
+ if (!dev->drv.drv_erase_fn)
return 0;
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
"checking blocks %d to %d",
dev->n_erasures++;
- result = dev->param.erase_fn(dev, offset_i);
+ result = dev->drv.drv_erase_fn(dev, offset_i);
if(result) {
bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
dev->n_erased_blocks++;
dev->n_free_chunks +=
dev->param.chunks_per_block;
} else {
- dev->param.bad_block_fn(dev, offset_i);
+ dev->drv.drv_mark_bad_fn(dev, offset_i);
bi->block_state = YAFFS_BLOCK_STATE_DEAD;
}
}
enum yaffs_block_state state;
u32 seq;
- dev->param.read_chunk_tags_fn(dev,
+ dev->tagger.read_chunk_tags_fn(dev,
apply_chunk_offset(dev, chunk),
NULL, &tags);
yaffs_trace(YAFFS_TRACE_CHECKPOINT,
if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
continue;
- dev->param.query_block_fn(dev,
+ dev->tagger.query_block_fn(dev,
apply_block_offset(dev, i),
&state, &seq);
if (state == YAFFS_BLOCK_STATE_DEAD)
dev->checkpt_open_write = writing;
/* Got the functions we need? */
- if (!dev->param.write_chunk_tags_fn ||
- !dev->param.read_chunk_tags_fn ||
- !dev->param.erase_fn || !dev->param.bad_block_fn)
+ if (!dev->tagger.write_chunk_tags_fn ||
+ !dev->tagger.read_chunk_tags_fn ||
+ !dev->drv.drv_erase_fn ||
+ !dev->drv.drv_mark_bad_fn)
return 0;
if (writing && !yaffs2_checkpt_space_ok(dev))
dev->n_page_writes++;
- dev->param.write_chunk_tags_fn(dev, offset_chunk,
+ dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
dev->checkpt_buffer, &tags);
dev->checkpt_page_seq++;
dev->checkpt_cur_chunk++;
dev->n_page_reads++;
/* read in the next chunk */
- dev->param.read_chunk_tags_fn(dev,
+ dev->tagger.read_chunk_tags_fn(dev,
offset_chunk,
dev->checkpt_buffer,
&tags);
#include "yaffs_guts.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_tagscompat.h"
+#include "yaffs_tagsmarshall.h"
#include "yaffs_nand.h"
#include "yaffs_yaffs1.h"
#include "yaffs_yaffs2.h"
memset(buffer, 0xff, dev->data_bytes_per_chunk);
memset(&tags, 0, sizeof(tags));
tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
- if (dev->param.write_chunk_tags_fn(dev, chunk_id -
- dev->chunk_offset,
- buffer,
- &tags) != YAFFS_OK)
+ if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
+ dev->chunk_offset,
+ buffer,
+ &tags) != YAFFS_OK)
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs: Failed to write bad block marker to block %d",
flash_block);
int erased_chunks;
int checkpt_block_adjust;
- if (dev->param.gc_control && (dev->param.gc_control(dev) & 1) == 0)
+ if (dev->param.gc_control_fn &&
+ (dev->param.gc_control_fn(dev) & 1) == 0)
return YAFFS_OK;
if (dev->gc_disable)
}
if (n_copy != dev->data_bytes_per_chunk ||
+ !dev->param.cache_bypass_aligned ||
dev->param.inband_tags) {
/* An incomplete start or end chunk (or maybe both
* start and end chunk), or we're using inband tags,
+ * or we're forcing writes through the cache,
* so we want to use the cache buffers.
*/
if (dev->param.n_caches > 0) {
/*--------------------------- Initialisation code -------------------------- */
-static int yaffs_check_dev_fns(const struct yaffs_dev *dev)
+static int yaffs_check_dev_fns(struct yaffs_dev *dev)
{
+ struct yaffs_driver *drv = &dev->drv;
+ struct yaffs_tags_handler *tagger = &dev->tagger;
+
/* Common functions, gotta have */
- if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
+ if (!drv->drv_read_chunk_fn ||
+ !drv->drv_write_chunk_fn ||
+ !drv->drv_erase_fn)
return 0;
- /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
- if (dev->param.write_chunk_tags_fn &&
- dev->param.read_chunk_tags_fn &&
- !dev->param.write_chunk_fn &&
- !dev->param.read_chunk_fn &&
- dev->param.bad_block_fn && dev->param.query_block_fn)
- return 1;
+ if (dev->param.is_yaffs2 &&
+ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
+ return 0;
- /* Can use the "spare" style interface for yaffs1 */
- if (!dev->param.is_yaffs2 &&
- !dev->param.write_chunk_tags_fn &&
- !dev->param.read_chunk_tags_fn &&
- dev->param.write_chunk_fn &&
- dev->param.read_chunk_fn &&
- !dev->param.bad_block_fn && !dev->param.query_block_fn)
- return 1;
+ /* Install the default tags marshalling functions if needed. */
+ yaffs_tags_compat_install(dev);
+ yaffs_tags_marshall_install(dev);
- return 0; /* bad */
+ /* Check we now have the marshalling functions required. */
+ if (!tagger->write_chunk_tags_fn ||
+ !tagger->read_chunk_tags_fn ||
+ !tagger->query_block_fn ||
+ !tagger->mark_bad_fn)
+ return 0;
+
+ return 1;
}
static int yaffs_create_initial_dir(struct yaffs_dev *dev)
dev->is_mounted = 0;
- if (dev->param.deinitialise_flash_fn)
- dev->param.deinitialise_flash_fn(dev);
+ yaffs_deinit_nand(dev);
}
}
/*
* Entry parameters set up way early. Yaffs sets up the rest.
* The structure should be zeroed out before use so that unused
- * and defualt values are zero.
+ * and default values are zero.
*/
int inband_tags; /* Use unband tags */
int n_caches; /* If <= 0, then short op caching is disabled,
* else the number of short op caches.
*/
+ int cache_bypass_aligned; /* If non-zero then bypass the cache for
+ * aligned writes.
+ */
+
int use_nand_ecc; /* Flag to decide whether or not to use
* NAND driver ECC on data (yaffs1) */
int tags_9bytes; /* Use 9 byte tags */
int enable_xattr; /* Enable xattribs */
- /* NAND access functions (Must be set before calling YAFFS) */
-
- int (*write_chunk_fn) (struct yaffs_dev *dev,
- int nand_chunk, const u8 *data,
- const struct yaffs_spare *spare);
- int (*read_chunk_fn) (struct yaffs_dev *dev,
- int nand_chunk, u8 *data,
- struct yaffs_spare *spare);
- int (*erase_fn) (struct yaffs_dev *dev, int flash_block);
- int (*initialise_flash_fn) (struct yaffs_dev *dev);
- int (*deinitialise_flash_fn) (struct yaffs_dev *dev);
-
- /* yaffs2 mode functions */
- int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
- int nand_chunk, const u8 *data,
- const struct yaffs_ext_tags *tags);
- int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
- int nand_chunk, u8 *data,
- struct yaffs_ext_tags *tags);
- int (*bad_block_fn) (struct yaffs_dev *dev, int block_no);
- int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
- enum yaffs_block_state *state,
- u32 *seq_number);
+ int max_objects; /*
+ * Set to limit the number of objects created.
+ * 0 = no limit.
+ */
/* The remove_obj_fn function must be supplied by OS flavours that
* need it.
void (*sb_dirty_fn) (struct yaffs_dev *dev);
/* Callback to control garbage collection. */
- unsigned (*gc_control) (struct yaffs_dev *dev);
+ unsigned (*gc_control_fn) (struct yaffs_dev *dev);
/* Debug control flags. Don't use unless you know what you're doing */
int use_header_file_size; /* Flag to determine if we should use
int disable_summary;
- int max_objects; /*
- * Set to limit the number of objects created.
- * 0 = no limit.
- */
+};
+
+struct yaffs_driver {
+ int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
+ const u8 *data, int data_len,
+ const u8 *oob, int oob_len);
+ int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
+ u8 *data, int data_len,
+ u8 *oob, int oob_len,
+ enum yaffs_ecc_result *ecc_result);
+ int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
+ int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
+ int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
+ int (*drv_initialise_fn) (struct yaffs_dev *dev);
+ int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
+};
+
+struct yaffs_tags_handler {
+ int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
+ int nand_chunk, const u8 *data,
+ const struct yaffs_ext_tags *tags);
+ int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
+ int nand_chunk, u8 *data,
+ struct yaffs_ext_tags *tags);
+
+ int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number);
+ int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
};
struct yaffs_dev {
struct yaffs_param param;
+ struct yaffs_driver drv;
+ struct yaffs_tags_handler tagger;
/* Context storage. Holds extra OS specific data for this device */
u32 n_page_writes;
u32 n_page_reads;
u32 n_erasures;
+ u32 n_bad_markings;
u32 n_erase_failures;
u32 n_gc_copies;
u32 all_gcs;
* at compile time so we have to allocate it.
*/
struct list_head search_contexts;
- void (*put_super_fn) (struct super_block *sb);
-
struct task_struct *readdir_process;
unsigned mount_id;
};
+++ /dev/null
-/*
- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "yportenv.h"
-
-#include "yaffs_mtdif.h"
-
-#include "linux/mtd/mtd.h"
-#include "linux/types.h"
-#include "linux/time.h"
-#include "linux/mtd/nand.h"
-
-#include "yaffs_linux.h"
-
-int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- u32 addr =
- ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
- dev->param.chunks_per_block;
- struct erase_info ei;
- int retval = 0;
-
- ei.mtd = mtd;
- ei.addr = addr;
- ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
- ei.time = 1000;
- ei.retries = 2;
- ei.callback = NULL;
- ei.priv = (u_long) dev;
-
- retval = mtd->erase(mtd, &ei);
-
- if (retval == 0)
- return YAFFS_OK;
-
- return YAFFS_FAIL;
-}
-
-int nandmtd_initialise(struct yaffs_dev *dev)
-{
- return YAFFS_OK;
-}
#include "yaffs_guts.h"
-int nandmtd_erase_block(struct yaffs_dev *dev, int block_no);
-int nandmtd_initialise(struct yaffs_dev *dev);
+void yaffs_mtd_drv_install(struct yaffs_dev *dev);
+
#endif
+++ /dev/null
-/*
- * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1 as
- * published by the Free Software Foundation.
- *
- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
- */
-
-#ifndef __YAFFS_MTDIF1_H__
-#define __YAFFS_MTDIF1_H__
-
-int nandmtd1_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
- const u8 *data,
- const struct yaffs_ext_tags *tags);
-
-int nandmtd1_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
- u8 *data, struct yaffs_ext_tags *tags);
-
-int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no);
-
-int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
- enum yaffs_block_state *state, u32 *seq_number);
-
-#endif
+++ /dev/null
-/*
- * YAFFS: Yet another FFS. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * This module provides the interface between yaffs_nand.c and the
- * MTD API. This version is used when the MTD interface supports the
- * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
- * and we have small-page NAND device.
- *
- * These functions are invoked via function pointers in yaffs_nand.c.
- * This replaces functionality provided by functions in yaffs_mtdif.c
- * and the yaffs_tags compatability functions in yaffs_tagscompat.c that are
- * called in yaffs_mtdif.c when the function pointers are NULL.
- * We assume the MTD layer is performing ECC (use_nand_ecc is true).
- */
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-#include "yaffs_guts.h"
-#include "yaffs_packedtags1.h"
-#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
-#include "yaffs_linux.h"
-
-#include "linux/kernel.h"
-#include "linux/version.h"
-#include "linux/types.h"
-#include "linux/mtd/mtd.h"
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
-#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
-#endif
-
-
-/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
-#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
-
-
-#if 0
-/* Use the following nand_ecclayout with MTD when using
- * 9 byte tags and the older on-NAND tags layout.
- * If you have existing Yaffs images and the byte order differs from this,
- * adjust 'oobfree' to match your existing Yaffs data.
- *
- * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
- * page_status byte (at NAND spare offset 4) scattered/gathered from/to
- * the 9th byte.
- *
- * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
- * We have/need packed_tags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
- * where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
- * byte and B is the small-page bad-block indicator byte.
- */
-static struct nand_ecclayout nand_oob_16 = {
- .eccbytes = 6,
- .eccpos = {8, 9, 10, 13, 14, 15},
- .oobavail = 9,
- .oobfree = {{0, 4}, {6, 2}, {11, 2}, {4, 1} }
-};
-#endif
-
-/* Write a chunk (page) of data to NAND.
- *
- * Caller always provides ExtendedTags data which are converted to a more
- * compact (packed) form for storage in NAND. A mini-ECC runs over the
- * contents of the tags meta-data; used to valid the tags when read.
- *
- * - Pack ExtendedTags to packed_tags1 form
- * - Compute mini-ECC for packed_tags1
- * - Write data and packed tags to NAND.
- *
- * Note: Due to the use of the packed_tags1 meta-data which does not include
- * a full sequence number (as found in the larger packed_tags2 form) it is
- * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
- * discarded and dirty. This is not ideal: newer NAND parts are supposed
- * to be written just once. When Yaffs performs this operation, this
- * function is called with a NULL data pointer -- calling MTD write_oob
- * without data is valid usage (2.6.17).
- *
- * Any underlying MTD error results in YAFFS_FAIL.
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
- int nand_chunk, const u8 *data,
- const struct yaffs_ext_tags *etags)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int chunk_bytes = dev->data_bytes_per_chunk;
- loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
- struct mtd_oob_ops ops;
- struct yaffs_packed_tags1 pt1;
- int retval;
-
- /* we assume that packed_tags1 and struct yaffs_tags are compatible */
- compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
- compile_time_assertion(sizeof(struct yaffs_tags) == 8);
-
- yaffs_pack_tags1(&pt1, etags);
- yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
-
- /* When deleting a chunk, the upper layer provides only skeletal
- * etags, one with is_deleted set. However, we need to update the
- * tags, not erase them completely. So we use the NAND write property
- * that only zeroed-bits stick and set tag bytes to all-ones and
- * zero just the (not) deleted bit.
- */
- if(dev->param.tags_9bytes) {
- ((u8 *) &pt1)[8] = 0xff;
- if (etags->is_deleted) {
- memset(&pt1, 0xff, 8);
- /* zero page_status byte to indicate deleted */
- ((u8 *) &pt1)[8] = 0;
- }
- } else {
- if (etags->is_deleted) {
- memset(&pt1, 0xff, 8);
- /* clear delete status bit to indicate deleted */
- pt1.deleted = 0;
- }
- }
-
- memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.len = (data) ? chunk_bytes : 0;
- ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
- ops.datbuf = (u8 *) data;
- ops.oobbuf = (u8 *) &pt1;
-
- retval = mtd->write_oob(mtd, addr, &ops);
- if (retval) {
- yaffs_trace(YAFFS_TRACE_MTD,
- "write_oob failed, chunk %d, mtd error %d",
- nand_chunk, retval);
- }
- return retval ? YAFFS_FAIL : YAFFS_OK;
-}
-
-/* Return with empty ExtendedTags but add ecc_result.
- */
-static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval)
-{
- if (etags) {
- memset(etags, 0, sizeof(*etags));
- etags->ecc_result = ecc_result;
- }
- return retval;
-}
-
-/* Read a chunk (page) from NAND.
- *
- * Caller expects ExtendedTags data to be usable even on error; that is,
- * all members except ecc_result and block_bad are zeroed.
- *
- * - Check ECC results for data (if applicable)
- * - Check for blank/erased block (return empty ExtendedTags if blank)
- * - Check the packed_tags1 mini-ECC (correct if necessary/possible)
- * - Convert packed_tags1 to ExtendedTags
- * - Update ecc_result and block_bad members to refect state.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
- int nand_chunk, u8 *data,
- struct yaffs_ext_tags *etags)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int chunk_bytes = dev->data_bytes_per_chunk;
- loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
- int eccres = YAFFS_ECC_RESULT_NO_ERROR;
- struct mtd_oob_ops ops;
- struct yaffs_packed_tags1 pt1;
- int retval;
- int deleted;
-
- memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.len = (data) ? chunk_bytes : 0;
- ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
- ops.datbuf = data;
- ops.oobbuf = (u8 *) &pt1;
-
-#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
- /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
- * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
- */
- ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
-#endif
- /* Read page and oob using MTD.
- * Check status and determine ECC result.
- */
- retval = mtd->read_oob(mtd, addr, &ops);
- if (retval)
- yaffs_trace(YAFFS_TRACE_MTD,
- "read_oob failed, chunk %d, mtd error %d",
- nand_chunk, retval);
-
- switch (retval) {
- case 0:
- /* no error */
- break;
-
- case -EUCLEAN:
- /* MTD's ECC fixed the data */
- eccres = YAFFS_ECC_RESULT_FIXED;
- dev->n_ecc_fixed++;
- break;
-
- case -EBADMSG:
- /* MTD's ECC could not fix the data */
- dev->n_ecc_unfixed++;
- /* fall into... */
- default:
- rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
- etags->block_bad = (mtd->block_isbad) (mtd, addr);
- return YAFFS_FAIL;
- }
-
- /* Check for a blank/erased chunk.
- */
- if (yaffs_check_ff((u8 *) &pt1, 8)) {
- /* when blank, upper layers want ecc_result to be <= NO_ERROR */
- return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
- }
-
- if(dev->param.tags_9bytes) {
- deleted = (hweight8(((u8 *) &pt1)[8]) < 7);
- } else {
- /* Read deleted status (bit) then return it to it's non-deleted
- * state before performing tags mini-ECC check. pt1.deleted is
- * inverted.
- */
- deleted = !pt1.deleted;
- pt1.deleted = 1;
- }
-
- /* Check the packed tags mini-ECC and correct if necessary/possible.
- */
- retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
- switch (retval) {
- case 0:
- /* no tags error, use MTD result */
- break;
- case 1:
- /* recovered tags-ECC error */
- dev->n_tags_ecc_fixed++;
- if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
- eccres = YAFFS_ECC_RESULT_FIXED;
- break;
- default:
- /* unrecovered tags-ECC error */
- dev->n_tags_ecc_unfixed++;
- return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
- }
-
- /* Unpack the tags to extended form and set ECC result.
- * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
- */
- pt1.should_be_ff = 0xffffffff;
- yaffs_unpack_tags1(etags, &pt1);
- etags->ecc_result = eccres;
-
- /* Set deleted state */
- etags->is_deleted = deleted;
- return YAFFS_OK;
-}
-
-/* Mark a block bad.
- *
- * This is a persistant state.
- * Use of this function should be rare.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
- int retval;
-
- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
-
- retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
- return (retval) ? YAFFS_FAIL : YAFFS_OK;
-}
-
-/* Check any MTD prerequists.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-static int nandmtd1_test_prerequists(struct yaffs_dev *dev, struct mtd_info *mtd)
-{
- /* 2.6.18 has mtd->ecclayout->oobavail */
- /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
- int oobavail = mtd->ecclayout->oobavail;
-
- if (oobavail < (dev->param.tags_9bytes ? 9 : 8)) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "mtd device has only %d bytes for tags, need %d",
- oobavail, dev->param.tags_9bytes ? 9 : 8);
- return YAFFS_FAIL;
- }
- return YAFFS_OK;
-}
-
-/* Query for the current state of a specific block.
- *
- * Examine the tags of the first chunk of the block and return the state:
- * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
- * - YAFFS_BLOCK_STATE_NEEDS_SCAN, the block is in use
- * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
- *
- * Always returns YAFFS_OK.
- */
-int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
- enum yaffs_block_state *state_ptr, u32 * seq_ptr)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int chunk_num = block_no * dev->param.chunks_per_block;
- loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk;
- struct yaffs_ext_tags etags;
- int state = YAFFS_BLOCK_STATE_DEAD;
- int seqnum = 0;
- int retval;
-
- /* We don't yet have a good place to test for MTD config prerequists.
- * Do it here as we are called during the initial scan.
- */
- if (nandmtd1_test_prerequists(dev, mtd) != YAFFS_OK)
- return YAFFS_FAIL;
-
- retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags);
- etags.block_bad = (mtd->block_isbad) (mtd, addr);
- if (etags.block_bad) {
- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
- "block %d is marked bad",
- block_no);
- state = YAFFS_BLOCK_STATE_DEAD;
- } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
- /* bad tags, need to look more closely */
- state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
- } else if (etags.chunk_used) {
- state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
- seqnum = etags.seq_number;
- } else {
- state = YAFFS_BLOCK_STATE_EMPTY;
- }
-
- *state_ptr = state;
- *seq_ptr = seqnum;
-
- /* query always succeeds */
- return YAFFS_OK;
-}
-
-#endif /*MTD_VERSION */
+++ /dev/null
-/*
- * YAFFS: Yet another FFS. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * This module provides the interface between yaffs_nand.c and the
- * MTD API. This version is used when the MTD interface supports the
- * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
- * and we have small-page NAND device.
- *
- * These functions are invoked via function pointers in yaffs_nand.c.
- * This replaces functionality provided by functions in yaffs_mtdif.c
- * and the yaffs_tags compatability functions in yaffs_tagscompat.c that are
- * called in yaffs_mtdif.c when the function pointers are NULL.
- * We assume the MTD layer is performing ECC (use_nand_ecc is true).
- */
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-#include "yaffs_guts.h"
-#include "yaffs_packedtags1.h"
-#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
-#include "yaffs_linux.h"
-#include "linux/kernel.h"
-#include "linux/version.h"
-#include "linux/types.h"
-#include "linux/mtd/mtd.h"
-
-/* Write a chunk (page) of data to NAND.
- *
- * Caller always provides ExtendedTags data which are converted to a more
- * compact (packed) form for storage in NAND. A mini-ECC runs over the
- * contents of the tags meta-data; used to valid the tags when read.
- *
- * - Pack ExtendedTags to packed_tags1 form
- * - Compute mini-ECC for packed_tags1
- * - Write data and packed tags to NAND.
- *
- * Note: Due to the use of the packed_tags1 meta-data which does not include
- * a full sequence number (as found in the larger packed_tags2 form) it is
- * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
- * discarded and dirty. This is not ideal: newer NAND parts are supposed
- * to be written just once. When Yaffs performs this operation, this
- * function is called with a NULL data pointer -- calling MTD write_oob
- * without data is valid usage (2.6.17).
- *
- * Any underlying MTD error results in YAFFS_FAIL.
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
- int nand_chunk, const u8 *data,
- const struct yaffs_ext_tags *etags)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int chunk_bytes = dev->data_bytes_per_chunk;
- loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
- struct mtd_oob_ops ops;
- struct yaffs_packed_tags1 pt1;
- int retval;
-
- /* we assume that packed_tags1 and struct yaffs_tags are compatible */
- compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
- compile_time_assertion(sizeof(struct yaffs_tags) == 8);
-
- yaffs_pack_tags1(&pt1, etags);
- yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
-
- /* When deleting a chunk, the upper layer provides only skeletal
- * etags, one with is_deleted set. However, we need to update the
- * tags, not erase them completely. So we use the NAND write property
- * that only zeroed-bits stick and set tag bytes to all-ones and
- * zero just the (not) deleted bit.
- */
-
- if (dev->param.tags_9bytes) {
- ((u8 *) &pt1)[8] = 0xff;
- if (etags->is_deleted) {
- memset(&pt1, 0xff, 8);
- /* zero page_status byte to indicate deleted */
- ((u8 *) &pt1)[8] = 0;
- }
- } else {
- if (etags->is_deleted) {
- memset(&pt1, 0xff, 8);
- /* clear delete status bit to indicate deleted */
- pt1.deleted = 0;
- }
- }
-
- memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.len = (data) ? chunk_bytes : 0;
- ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
- ops.datbuf = (u8 *) data;
- ops.oobbuf = (u8 *) &pt1;
-
- retval = mtd->write_oob(mtd, addr, &ops);
- if (retval) {
- yaffs_trace(YAFFS_TRACE_MTD,
- "write_oob failed, chunk %d, mtd error %d",
- nand_chunk, retval);
- }
- return retval ? YAFFS_FAIL : YAFFS_OK;
-}
-
-/* Return with empty ExtendedTags but add ecc_result.
- */
-static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval)
-{
- if (etags) {
- memset(etags, 0, sizeof(*etags));
- etags->ecc_result = ecc_result;
- }
- return retval;
-}
-
-/* Read a chunk (page) from NAND.
- *
- * Caller expects ExtendedTags data to be usable even on error; that is,
- * all members except ecc_result and block_bad are zeroed.
- *
- * - Check ECC results for data (if applicable)
- * - Check for blank/erased block (return empty ExtendedTags if blank)
- * - Check the packed_tags1 mini-ECC (correct if necessary/possible)
- * - Convert packed_tags1 to ExtendedTags
- * - Update ecc_result and block_bad members to refect state.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
- int nand_chunk, u8 *data,
- struct yaffs_ext_tags *etags)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int chunk_bytes = dev->data_bytes_per_chunk;
- loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
- int eccres = YAFFS_ECC_RESULT_NO_ERROR;
- struct mtd_oob_ops ops;
- struct yaffs_packed_tags1 pt1;
- int retval;
- int deleted;
-
- memset(&ops, 0, sizeof(ops));
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.len = (data) ? chunk_bytes : 0;
- ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
- ops.datbuf = data;
- ops.oobbuf = (u8 *) &pt1;
-
- /* Read page and oob using MTD.
- * Check status and determine ECC result.
- */
- retval = mtd->read_oob(mtd, addr, &ops);
- if (retval) {
- yaffs_trace(YAFFS_TRACE_MTD,
- "read_oob failed, chunk %d, mtd error %d",
- nand_chunk, retval);
- }
-
- switch (retval) {
- case 0:
- /* no error */
- break;
-
- case -EUCLEAN:
- /* MTD's ECC fixed the data */
- eccres = YAFFS_ECC_RESULT_FIXED;
- dev->n_ecc_fixed++;
- break;
-
- case -EBADMSG:
- /* MTD's ECC could not fix the data */
- dev->n_ecc_unfixed++;
- /* fall into... */
- default:
- rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
- etags->block_bad = (mtd->block_isbad) (mtd, addr);
- return YAFFS_FAIL;
- }
-
- /* Check for a blank/erased chunk.
- */
- if (yaffs_check_ff((u8 *) &pt1, 8)) {
- /* when blank, upper layers want ecc_result to be <= NO_ERROR */
- return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
- }
-#ifndef CONFIG_YAFFS_9BYTE_TAGS
- /* Read deleted status (bit) then return it to it's non-deleted
- * state before performing tags mini-ECC check. pt1.deleted is
- * inverted.
- */
- deleted = !pt1.deleted;
- pt1.deleted = 1;
-#else
- deleted = (hweight8(((u8 *) &pt1)[8]) < 7);
-#endif
-
- /* Check the packed tags mini-ECC and correct if necessary/possible.
- */
- retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
- switch (retval) {
- case 0:
- /* no tags error, use MTD result */
- break;
- case 1:
- /* recovered tags-ECC error */
- dev->n_tags_ecc_fixed++;
- if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
- eccres = YAFFS_ECC_RESULT_FIXED;
- break;
- default:
- /* unrecovered tags-ECC error */
- dev->n_tags_ecc_unfixed++;
- return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
- }
-
- /* Unpack the tags to extended form and set ECC result.
- * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
- */
- pt1.should_be_ff = 0xffffffff;
- yaffs_unpack_tags1(etags, &pt1);
- etags->ecc_result = eccres;
-
- /* Set deleted state */
- etags->is_deleted = deleted;
- return YAFFS_OK;
-}
-
-/* Mark a block bad.
- *
- * This is a persistant state.
- * Use of this function should be rare.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
- int retval;
-
- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
- "marking block %d bad", block_no);
-
- retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
- return (retval) ? YAFFS_FAIL : YAFFS_OK;
-}
-
-/* Check any MTD prerequists.
- *
- * Returns YAFFS_OK or YAFFS_FAIL.
- */
-static int nandmtd1_test_prerequists(struct yaffs_dev *dev,
- struct mtd_info *mtd)
-{
- /* 2.6.18 has mtd->ecclayout->oobavail */
- /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
- int oobavail = mtd->ecclayout->oobavail;
-
- if (oobavail < (dev->param.tags_9bytes ? 9 : 8)) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "mtd device has only %d bytes for tags, need %d",
- oobavail, (dev->param.tags_9bytes ? 9 : 8));
- return YAFFS_FAIL;
- }
- return YAFFS_OK;
-}
-
-/* Query for the current state of a specific block.
- *
- * Examine the tags of the first chunk of the block and return the state:
- * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
- * - YAFFS_BLOCK_STATE_NEEDS_SCAN, the block is in use
- * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
- *
- * Always returns YAFFS_OK.
- */
-int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
- enum yaffs_block_state *state_ptr, u32 * seq_ptr)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int chunk_num = block_no * dev->param.chunks_per_block;
- loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk;
- struct yaffs_ext_tags etags;
- int state = YAFFS_BLOCK_STATE_DEAD;
- int seqnum = 0;
- int retval;
-
- /* We don't yet have a good place to test for MTD config prerequists.
- * Do it here as we are called during the initial scan.
- */
- if (nandmtd1_test_prerequists(dev, mtd) != YAFFS_OK)
- return YAFFS_FAIL;
-
- retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags);
- etags.block_bad = (mtd->block_isbad) (mtd, addr);
- if (etags.block_bad) {
- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
- "block %d is marked bad", block_no);
- state = YAFFS_BLOCK_STATE_DEAD;
- } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
- /* bad tags, need to look more closely */
- state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
- } else if (etags.chunk_used) {
- state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
- seqnum = etags.seq_number;
- } else {
- state = YAFFS_BLOCK_STATE_EMPTY;
- }
-
- *state_ptr = state;
- *seq_ptr = seqnum;
-
- /* query always succeeds */
- return YAFFS_OK;
-}
+++ /dev/null
-/*
- * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1 as
- * published by the Free Software Foundation.
- *
- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
- */
-
-#ifndef __YAFFS_MTDIF2_H__
-#define __YAFFS_MTDIF2_H__
-
-#include "yaffs_guts.h"
-int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
- const u8 *data,
- const struct yaffs_ext_tags *tags);
-int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
- u8 *data, struct yaffs_ext_tags *tags);
-int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no);
-int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
- enum yaffs_block_state *state, u32 *seq_number);
-
-#endif
+++ /dev/null
-/*
- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* mtd interface for YAFFS2 */
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-
-#include "yaffs_mtdif2.h"
-
-#include "linux/mtd/mtd.h"
-#include "linux/types.h"
-#include "linux/time.h"
-
-#include "yaffs_packedtags2.h"
-
-#include "yaffs_linux.h"
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
-#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
-#endif
-
-
-
-/* NB For use with inband tags....
- * We assume that the data buffer is of size total_bytes_per_chunk so
- * that we can also use it to load the tags.
- */
-int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
- const u8 *data,
- const struct yaffs_ext_tags *tags)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
- struct mtd_oob_ops ops;
-#else
- size_t dummy;
-#endif
- int retval = 0;
-
- loff_t addr;
-
- struct yaffs_packed_tags2 pt;
-
- int packed_tags_size =
- dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
- void *packed_tags_ptr =
- dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
-
- yaffs_trace(YAFFS_TRACE_MTD,
- "nandmtd2_write_chunk_tags chunk %d data %p tags %p",
- nand_chunk, data, tags);
-
- addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
-
- /* For yaffs2 writing there must be both data and tags.
- * If we're using inband tags, then the tags are stuffed into
- * the end of the data buffer.
- */
- if (!data || !tags)
- BUG();
- else if (dev->param.inband_tags) {
- struct yaffs_packed_tags2_tags_only *pt2tp;
- pt2tp =
- (struct yaffs_packed_tags2_tags_only *)(data +
- dev->
- data_bytes_per_chunk);
- yaffs_pack_tags2_tags_only(pt2tp, tags);
- } else {
- yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
- }
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
- ops.len = dev->param.total_bytes_per_chunk;
- ops.ooboffs = 0;
- ops.datbuf = (u8 *) data;
- ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
- retval = mtd->write_oob(mtd, addr, &ops);
-
-#else
- if (!dev->param.inband_tags) {
- retval =
- mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
- &dummy, data, (u8 *) packed_tags_ptr, NULL);
- } else {
- retval =
- mtd->write(mtd, addr, dev->param.total_bytes_per_chunk,
- &dummy, data);
- }
-#endif
-
- if (retval == 0)
- return YAFFS_OK;
- else
- return YAFFS_FAIL;
-}
-
-int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
- u8 *data, struct yaffs_ext_tags *tags)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
-#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
- struct mtd_oob_ops ops;
-#endif
- size_t dummy;
- int retval = 0;
- int local_data = 0;
-
- loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
-
- struct yaffs_packed_tags2 pt;
-
- int packed_tags_size =
- dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
- void *packed_tags_ptr =
- dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
-
- yaffs_trace(YAFFS_TRACE_MTD,
- "nandmtd2_read_chunk_tags chunk %d data %p tags %p",
- nand_chunk, data, tags);
-
- if (dev->param.inband_tags) {
-
- if (!data) {
- local_data = 1;
- data = yaffs_get_temp_buffer(dev);
- }
-
- }
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- if (dev->param.inband_tags || (data && !tags))
- retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
- &dummy, data);
- else if (tags) {
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.ooblen = packed_tags_size;
- ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
- ops.ooboffs = 0;
- ops.datbuf = data;
- ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
- retval = mtd->read_oob(mtd, addr, &ops);
- }
-#else
- if (!dev->param.inband_tags && data && tags) {
-
- retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
- &dummy, data, dev->spare_buffer, NULL);
- } else {
- if (data)
- retval =
- mtd->read(mtd, addr, dev->data_bytes_per_chunk,
- &dummy, data);
- if (!dev->param.inband_tags && tags)
- retval =
- mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
- dev->spare_buffer);
- }
-#endif
-
- if (dev->param.inband_tags) {
- if (tags) {
- struct yaffs_packed_tags2_tags_only *pt2tp;
- pt2tp =
- (struct yaffs_packed_tags2_tags_only *)
- &data[dev->data_bytes_per_chunk];
- yaffs_unpack_tags2_tags_only(tags, pt2tp);
- }
- } else {
- if (tags) {
- memcpy(packed_tags_ptr,
- yaffs_dev_to_lc(dev)->spare_buffer,
- packed_tags_size);
- yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
- }
- }
-
- if (local_data)
- yaffs_release_temp_buffer(dev, data);
-
- if (tags && retval == -EBADMSG
- && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
- tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
- dev->n_ecc_unfixed++;
- }
- if (tags && retval == -EUCLEAN
- && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
- tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
- dev->n_ecc_fixed++;
- }
- if (retval == 0)
- return YAFFS_OK;
- else
- return YAFFS_FAIL;
-}
-
-int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int retval;
- yaffs_trace(YAFFS_TRACE_MTD,
- "nandmtd2_mark_block_bad %d",
- block_no);
-
- retval =
- mtd->block_markbad(mtd,
- block_no * dev->param.chunks_per_block *
- dev->param.total_bytes_per_chunk);
-
- if (retval == 0)
- return YAFFS_OK;
- else
- return YAFFS_FAIL;
-
-}
-
-int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
- enum yaffs_block_state *state, u32 *seq_number)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int retval;
-
- yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no);
- retval =
- mtd->block_isbad(mtd,
- block_no * dev->param.chunks_per_block *
- dev->param.total_bytes_per_chunk);
-
- if (retval) {
- yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
-
- *state = YAFFS_BLOCK_STATE_DEAD;
- *seq_number = 0;
- } else {
- struct yaffs_ext_tags t;
- nandmtd2_read_chunk_tags(dev, block_no *
- dev->param.chunks_per_block, NULL, &t);
-
- if (t.chunk_used) {
- *seq_number = t.seq_number;
- *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
- } else {
- *seq_number = 0;
- *state = YAFFS_BLOCK_STATE_EMPTY;
- }
- }
- yaffs_trace(YAFFS_TRACE_MTD,
- "block is bad seq %d state %d",
- *seq_number, *state);
-
- if (retval == 0)
- return YAFFS_OK;
- else
- return YAFFS_FAIL;
-}
-
+++ /dev/null
-/*
- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
- *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
- *
- * Created by Charles Manning <charles@aleph1.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* mtd interface for YAFFS2 */
-
-#include "yportenv.h"
-#include "yaffs_trace.h"
-#include "yaffs_mtdif2.h"
-#include "yaffs_packedtags2.h"
-#include "yaffs_linux.h"
-#include "linux/mtd/mtd.h"
-#include "linux/types.h"
-#include "linux/time.h"
-#include "mtd/mtd-abi.h"
-
-
-/* NB For use with inband tags....
- * We assume that the data buffer is of size total_bytes_per_chunk so that
- * we can also use it to load the tags.
- */
-int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
- const u8 *data,
- const struct yaffs_ext_tags *tags)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- struct mtd_oob_ops ops;
- int retval = 0;
- loff_t addr;
- struct yaffs_packed_tags2 pt;
- int packed_tags_size =
- dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
- void *packed_tags_ptr =
- dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
-
- yaffs_trace(YAFFS_TRACE_MTD,
- "nandmtd2_write_chunk_tags chunk %d data %p tags %p",
- nand_chunk, data, tags);
-
- addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
-
- /* For yaffs2 writing there must be both data and tags.
- * If we're using inband tags, then the tags are stuffed into
- * the end of the data buffer.
- */
- if (!data || !tags)
- BUG();
- else if (dev->param.inband_tags) {
- struct yaffs_packed_tags2_tags_only *pt2tp;
-
- pt2tp =
- (struct yaffs_packed_tags2_tags_only *)
- (data + dev->data_bytes_per_chunk);
- yaffs_pack_tags2_tags_only(pt2tp, tags);
- } else {
- yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
- }
-
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
- ops.len = dev->param.total_bytes_per_chunk;
- ops.ooboffs = 0;
- ops.datbuf = (u8 *) data;
- ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
- retval = mtd->write_oob(mtd, addr, &ops);
-
- if (retval == 0)
- return YAFFS_OK;
-
- return YAFFS_FAIL;
-}
-
-int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
- u8 *data, struct yaffs_ext_tags *tags)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- struct mtd_oob_ops ops;
- size_t dummy;
- int retval = 0;
- int local_data = 0;
- loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
- struct yaffs_packed_tags2 pt;
- int packed_tags_size =
- dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
- void *packed_tags_ptr =
- dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
-
- yaffs_trace(YAFFS_TRACE_MTD,
- "nandmtd2_read_chunk_tags chunk %d data %p tags %p",
- nand_chunk, data, tags);
-
- if (dev->param.inband_tags && !data) {
- local_data = 1;
- data = yaffs_get_temp_buffer(dev);
- }
-
- if (dev->param.inband_tags || (data && !tags)) {
- retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
- &dummy, data);
- } else if (tags) {
- ops.mode = MTD_OPS_AUTO_OOB;
- ops.ooblen = packed_tags_size;
- ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
- ops.ooboffs = 0;
- ops.datbuf = data;
- ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
- retval = mtd->read_oob(mtd, addr, &ops);
- }
-
- if (dev->param.inband_tags && tags) {
- struct yaffs_packed_tags2_tags_only *pt2tp;
-
- pt2tp =
- (struct yaffs_packed_tags2_tags_only *)
- &data[dev->data_bytes_per_chunk];
- yaffs_unpack_tags2_tags_only(tags, pt2tp);
- } else if (tags) {
- memcpy(packed_tags_ptr,
- yaffs_dev_to_lc(dev)->spare_buffer,
- packed_tags_size);
- yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
- }
-
- if (local_data)
- yaffs_release_temp_buffer(dev, data);
-
- if (tags && retval == -EBADMSG &&
- tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
- tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
- dev->n_ecc_unfixed++;
- }
- if (tags && retval == -EUCLEAN &&
- tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
- tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
- dev->n_ecc_fixed++;
- }
-
- if (retval == 0)
- return YAFFS_OK;
-
- return YAFFS_FAIL;
-}
-
-int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int retval;
-
- yaffs_trace(YAFFS_TRACE_MTD,
- "nandmtd2_mark_block_bad %d", block_no);
-
- retval =
- mtd->block_markbad(mtd,
- block_no * dev->param.chunks_per_block *
- dev->param.total_bytes_per_chunk);
-
- if (retval == 0)
- return YAFFS_OK;
-
- return YAFFS_FAIL;
-}
-
-int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
- enum yaffs_block_state *state, u32 * seq_number)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- int retval;
-
- yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no);
- retval =
- mtd->block_isbad(mtd,
- block_no * dev->param.chunks_per_block *
- dev->param.total_bytes_per_chunk);
-
- if (retval) {
- yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
-
- *state = YAFFS_BLOCK_STATE_DEAD;
- *seq_number = 0;
- } else {
- struct yaffs_ext_tags t;
-
- nandmtd2_read_chunk_tags(dev, block_no *
- dev->param.chunks_per_block, NULL, &t);
-
- if (t.chunk_used) {
- *seq_number = t.seq_number;
- *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
- } else {
- *seq_number = 0;
- *state = YAFFS_BLOCK_STATE_EMPTY;
- }
- }
- yaffs_trace(YAFFS_TRACE_MTD,
- "block is bad seq %d state %d", *seq_number, *state);
-
- if (retval == 0)
- return YAFFS_OK;
-
- return YAFFS_FAIL;
-}
--- /dev/null
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yportenv.h"
+
+#include "yaffs_mtdif.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+#include "linux/mtd/nand.h"
+#include "linux/kernel.h"
+#include "linux/version.h"
+#include "linux/types.h"
+
+#include "yaffs_trace.h"
+#include "yaffs_guts.h"
+#include "yaffs_linux.h"
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
+#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
+#endif
+
+
+int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ u32 addr =
+ ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
+ dev->param.chunks_per_block;
+ struct erase_info ei;
+ int retval = 0;
+
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
+ ei.time = 1000;
+ ei.retries = 2;
+ ei.callback = NULL;
+ ei.priv = (u_long) dev;
+
+ retval = mtd->erase(mtd, &ei);
+
+ if (retval == 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
+}
+
+
+static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
+ const u8 *data, int data_len,
+ const u8 *oob, int oob_len)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ loff_t addr;
+ struct mtd_oob_ops ops;
+ int retval;
+
+ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
+ memset(&ops, 0, sizeof(ops));
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = (data) ? data_len : 0;
+ ops.ooblen = oob_len;
+ ops.datbuf = (u8 *)data;
+ ops.oobbuf = (u8 *)oob;
+
+ retval = mtd->write_oob(mtd, addr, &ops);
+ if (retval) {
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "write_oob failed, chunk %d, mtd error %d",
+ nand_chunk, retval);
+ }
+ return retval ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
+ u8 *data, int data_len,
+ u8 *oob, int oob_len,
+ enum yaffs_ecc_result *ecc_result)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ loff_t addr;
+ struct mtd_oob_ops ops;
+ int retval;
+
+ addr = ((loff_t) nand_chunk) * dev->data_bytes_per_chunk;
+ memset(&ops, 0, sizeof(ops));
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = (data) ? data_len : 0;
+ ops.ooblen = oob_len;
+ ops.datbuf = data;
+ ops.oobbuf = oob;
+
+#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
+ /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
+ * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
+ */
+ ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
+#endif
+ /* Read page and oob using MTD.
+ * Check status and determine ECC result.
+ */
+ retval = mtd->read_oob(mtd, addr, &ops);
+ if (retval)
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "read_oob failed, chunk %d, mtd error %d",
+ nand_chunk, retval);
+
+ switch (retval) {
+ case 0:
+ /* no error */
+ if(ecc_result)
+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+ break;
+
+ case -EUCLEAN:
+ /* MTD's ECC fixed the data */
+ if(ecc_result)
+ *ecc_result = YAFFS_ECC_RESULT_FIXED;
+ dev->n_ecc_fixed++;
+ break;
+
+ case -EBADMSG:
+ default:
+ /* MTD's ECC could not fix the data */
+ dev->n_ecc_unfixed++;
+ if(ecc_result)
+ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+ return YAFFS_FAIL;
+ }
+
+ return YAFFS_OK;
+}
+
+static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+
+ loff_t addr;
+ struct erase_info ei;
+ int retval = 0;
+ u32 block_size;
+
+ block_size = dev->param.total_bytes_per_chunk *
+ dev->param.chunks_per_block;
+ addr = ((loff_t) block_no) * block_size;
+
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = block_size;
+ ei.time = 1000;
+ ei.retries = 2;
+ ei.callback = NULL;
+ ei.priv = (u_long) dev;
+
+ retval = mtd->erase(mtd, &ei);
+
+ if (retval == 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
+}
+
+static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
+ int retval;
+
+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
+
+ retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
+ return (retval) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
+ int retval;
+
+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "checking block %d bad", block_no);
+
+ retval = mtd->block_isbad(mtd, (loff_t) blocksize * block_no);
+ return (retval) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_initialise(struct yaffs_dev *dev)
+{
+ return YAFFS_OK;
+}
+
+static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
+{
+ return YAFFS_OK;
+}
+
+
+
+void yaffs_mtd_drv_install(struct yaffs_dev *dev)
+{
+ struct yaffs_driver *drv = &dev->drv;
+
+ drv->drv_write_chunk_fn = yaffs_mtd_write;
+ drv->drv_read_chunk_fn = yaffs_mtd_read;
+ drv->drv_erase_fn = yaffs_mtd_erase;
+ drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
+ drv->drv_check_bad_fn = yaffs_mtd_check_bad;
+ drv->drv_initialise_fn = yaffs_mtd_initialise;
+ drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
+}
#include "yaffs_getblockinfo.h"
#include "yaffs_summary.h"
+static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
+{
+ return chunk - dev->chunk_offset;
+}
+
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
u8 *buffer, struct yaffs_ext_tags *tags)
{
int result;
struct yaffs_ext_tags local_tags;
- int flash_chunk = nand_chunk - dev->chunk_offset;
+ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
dev->n_page_reads++;
if (!tags)
tags = &local_tags;
- if (dev->param.read_chunk_tags_fn)
- result =
- dev->param.read_chunk_tags_fn(dev, flash_chunk, buffer,
- tags);
- else
- result = yaffs_tags_compat_rd(dev,
- flash_chunk, buffer, tags);
+ result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
struct yaffs_block_info *bi;
const u8 *buffer, struct yaffs_ext_tags *tags)
{
int result;
- int flash_chunk = nand_chunk - dev->chunk_offset;
+ int flash_chunk = apply_chunk_offset(dev, nand_chunk);
dev->n_page_writes++;
- if (tags) {
- tags->seq_number = dev->seq_number;
- tags->chunk_used = 1;
- yaffs_trace(YAFFS_TRACE_WRITE,
- "Writing chunk %d tags %d %d",
- nand_chunk, tags->obj_id, tags->chunk_id);
- } else {
+ if (!tags) {
yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
BUG();
return YAFFS_FAIL;
}
- if (dev->param.write_chunk_tags_fn)
- result = dev->param.write_chunk_tags_fn(dev, flash_chunk,
+ tags->seq_number = dev->seq_number;
+ tags->chunk_used = 1;
+ yaffs_trace(YAFFS_TRACE_WRITE,
+ "Writing chunk %d tags %d %d",
+ nand_chunk, tags->obj_id, tags->chunk_id);
+
+ result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
buffer, tags);
- else
- result = yaffs_tags_compat_wr(dev, flash_chunk, buffer, tags);
yaffs_summary_add(dev, tags, nand_chunk);
int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
{
block_no -= dev->block_offset;
- if (dev->param.bad_block_fn)
- return dev->param.bad_block_fn(dev, block_no);
-
- return yaffs_tags_compat_mark_bad(dev, block_no);
+ dev->n_bad_markings++;
+ return dev->tagger.mark_bad_fn(dev, block_no);
}
+
int yaffs_query_init_block_state(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
u32 *seq_number)
{
block_no -= dev->block_offset;
- if (dev->param.query_block_fn)
- return dev->param.query_block_fn(dev, block_no, state,
- seq_number);
-
- return yaffs_tags_compat_query_block(dev, block_no, state, seq_number);
+ return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
}
-int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
+int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
{
int result;
- flash_block -= dev->block_offset;
+ block_no -= dev->block_offset;
dev->n_erasures++;
- result = dev->param.erase_fn(dev, flash_block);
+ result = dev->drv.drv_erase_fn(dev, block_no);
return result;
}
int yaffs_init_nand(struct yaffs_dev *dev)
{
- if (dev->param.initialise_flash_fn)
- return dev->param.initialise_flash_fn(dev);
+ if (dev->drv.drv_initialise_fn)
+ return dev->drv.drv_initialise_fn(dev);
+ return YAFFS_OK;
+}
+
+int yaffs_deinit_nand(struct yaffs_dev *dev)
+{
+ if (dev->drv.drv_deinitialise_fn)
+ return dev->drv.drv_deinitialise_fn(dev);
return YAFFS_OK;
}
int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
int yaffs_init_nand(struct yaffs_dev *dev);
+int yaffs_deinit_nand(struct yaffs_dev *dev);
#endif
/********** Tags ECC calculations *********/
-static void yaffs_calc_ecc(const u8 *data, struct yaffs_spare *spare)
-{
- yaffs_ecc_calc(data, spare->ecc1);
- yaffs_ecc_calc(&data[256], spare->ecc2);
-}
void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
{
int nand_chunk, const u8 *data,
struct yaffs_spare *spare)
{
- if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>> yaffs chunk %d is not valid",
- nand_chunk);
- return YAFFS_FAIL;
- }
+ int data_size = dev->data_bytes_per_chunk;
- return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
+ return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
+ data, data_size,
+ (u8 *) spare, sizeof(*spare));
}
static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
{
int ret_val;
struct yaffs_spare local_spare;
+ int data_size;
+ int spare_size;
+ int ecc_result1, ecc_result2;
+ u8 calc_ecc[3];
if (!spare) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */
spare = &local_spare;
}
+ data_size = dev->data_bytes_per_chunk;
+ spare_size = sizeof(struct yaffs_spare);
- if (!dev->param.use_nand_ecc) {
- ret_val =
- dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
- if (data && correct_errors) {
- /* Do ECC correction */
- /* Todo handle any errors */
- int ecc_result1, ecc_result2;
- u8 calc_ecc[3];
-
- yaffs_ecc_calc(data, calc_ecc);
- ecc_result1 =
- yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
- yaffs_ecc_calc(&data[256], calc_ecc);
- ecc_result2 =
- yaffs_ecc_correct(&data[256], spare->ecc2,
- calc_ecc);
-
- if (ecc_result1 > 0) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>>yaffs ecc error fix performed on chunk %d:0",
- nand_chunk);
- dev->n_ecc_fixed++;
- } else if (ecc_result1 < 0) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>>yaffs ecc error unfixed on chunk %d:0",
- nand_chunk);
- dev->n_ecc_unfixed++;
- }
-
- if (ecc_result2 > 0) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>>yaffs ecc error fix performed on chunk %d:1",
- nand_chunk);
- dev->n_ecc_fixed++;
- } else if (ecc_result2 < 0) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>>yaffs ecc error unfixed on chunk %d:1",
- nand_chunk);
- dev->n_ecc_unfixed++;
- }
-
- if (ecc_result1 || ecc_result2) {
- /* We had a data problem on this page */
- yaffs_handle_rd_data_error(dev, nand_chunk);
- }
-
- if (ecc_result1 < 0 || ecc_result2 < 0)
- *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
- else if (ecc_result1 > 0 || ecc_result2 > 0)
- *ecc_result = YAFFS_ECC_RESULT_FIXED;
- else
- *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
- }
- } else {
- /* Must allocate enough memory for spare+2*sizeof(int) */
- /* for ecc results from device. */
- struct yaffs_nand_spare nspare;
-
- memset(&nspare, 0, sizeof(nspare));
-
- ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data,
- (struct yaffs_spare *)
- &nspare);
- memcpy(spare, &nspare, sizeof(struct yaffs_spare));
- if (data && correct_errors) {
- if (nspare.eccres1 > 0) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>>mtd ecc error fix performed on chunk %d:0",
- nand_chunk);
- } else if (nspare.eccres1 < 0) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>>mtd ecc error unfixed on chunk %d:0",
- nand_chunk);
- }
-
- if (nspare.eccres2 > 0) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>>mtd ecc error fix performed on chunk %d:1",
- nand_chunk);
- } else if (nspare.eccres2 < 0) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- "**>>mtd ecc error unfixed on chunk %d:1",
- nand_chunk);
- }
-
- if (nspare.eccres1 || nspare.eccres2) {
- /* We had a data problem on this page */
- yaffs_handle_rd_data_error(dev, nand_chunk);
- }
-
- if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
- *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
- else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
- *ecc_result = YAFFS_ECC_RESULT_FIXED;
- else
- *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+ if (dev->param.use_nand_ecc)
+ return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+ data, data_size,
+ (u8 *) spare, spare_size,
+ ecc_result);
- }
+
+ /* Handle the ECC at this level. */
+
+ ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+ data, data_size,
+ (u8 *)spare, spare_size,
+ NULL);
+ if (!data || !correct_errors)
+ return ret_val;
+
+ /* Do ECC correction if needed. */
+ yaffs_ecc_calc(data, calc_ecc);
+ ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
+ yaffs_ecc_calc(&data[256], calc_ecc);
+ ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
+
+ if (ecc_result1 > 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error fix performed on chunk %d:0",
+ nand_chunk);
+ dev->n_ecc_fixed++;
+ } else if (ecc_result1 < 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error unfixed on chunk %d:0",
+ nand_chunk);
+ dev->n_ecc_unfixed++;
}
+
+ if (ecc_result2 > 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error fix performed on chunk %d:1",
+ nand_chunk);
+ dev->n_ecc_fixed++;
+ } else if (ecc_result2 < 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error unfixed on chunk %d:1",
+ nand_chunk);
+ dev->n_ecc_unfixed++;
+ }
+
+ if (ecc_result1 || ecc_result2) {
+ /* We had a data problem on this page */
+ yaffs_handle_rd_data_error(dev, nand_chunk);
+ }
+
+ if (ecc_result1 < 0 || ecc_result2 < 0)
+ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+ else if (ecc_result1 > 0 || ecc_result2 > 0)
+ *ecc_result = YAFFS_ECC_RESULT_FIXED;
+ else
+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
return ret_val;
}
*/
}
-int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *ext_tags)
{
tags.serial_number = ext_tags->serial_number;
- if (!dev->param.use_nand_ecc && data)
- yaffs_calc_ecc(data, &spare);
+ if (!dev->param.use_nand_ecc && data) {
+ yaffs_ecc_calc(data, spare.ecc1);
+ yaffs_ecc_calc(&data[256], spare.ecc2);
+ }
yaffs_load_tags_to_spare(&spare, &tags);
}
return yaffs_wr_nand(dev, nand_chunk, data, &spare);
}
-int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
int nand_chunk,
u8 *data, struct yaffs_ext_tags *ext_tags)
{
return YAFFS_OK;
}
-int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
{
struct yaffs_spare spare;
return YAFFS_OK;
}
-int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
u32 *seq_number)
*seq_number = 0;
- yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
- &spare0, &dummy, 1);
+ /* Look for bad block markers in the first two chunks */
+ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
+ NULL, &spare0, &dummy, 0);
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
- NULL, &spare1, &dummy, 1);
+ NULL, &spare1, &dummy, 0);
if (hweight8(spare0.block_status & spare1.block_status) < 7)
*state = YAFFS_BLOCK_STATE_DEAD;
return YAFFS_OK;
}
+
+void yaffs_tags_compat_install(struct yaffs_dev *dev)
+{
+ if(dev->param.is_yaffs2)
+ return;
+ if(!dev->tagger.write_chunk_tags_fn)
+ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
+ if(!dev->tagger.read_chunk_tags_fn)
+ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
+ if(!dev->tagger.query_block_fn)
+ dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
+ if(!dev->tagger.mark_bad_fn)
+ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
+}
#ifndef __YAFFS_TAGSCOMPAT_H__
#define __YAFFS_TAGSCOMPAT_H__
+
#include "yaffs_guts.h"
+
+#if 0
+
+
int yaffs_tags_compat_wr(struct yaffs_dev *dev,
int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *tags);
enum yaffs_block_state *state,
u32 *seq_number);
+#endif
+
+
+void yaffs_tags_compat_install(struct yaffs_dev *dev);
void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
int yaffs_check_tags_ecc(struct yaffs_tags *tags);
-int yaffs_count_bits(u8 byte);
#endif
--- /dev/null
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yaffs_packedtags2.h"
+
+static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
+ int nand_chunk, const u8 *data,
+ const struct yaffs_ext_tags *tags)
+{
+ struct yaffs_packed_tags2 pt;
+ int retval;
+
+ int packed_tags_size =
+ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
+ void *packed_tags_ptr =
+ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
+
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "yaffs_tags_marshall_write chunk %d data %p tags %p",
+ nand_chunk, data, tags);
+
+ /* For yaffs2 writing there must be both data and tags.
+ * If we're using inband tags, then the tags are stuffed into
+ * the end of the data buffer.
+ */
+ if (!data || !tags)
+ BUG();
+ else if (dev->param.inband_tags) {
+ struct yaffs_packed_tags2_tags_only *pt2tp;
+ pt2tp =
+ (struct yaffs_packed_tags2_tags_only *)(data +
+ dev->
+ data_bytes_per_chunk);
+ yaffs_pack_tags2_tags_only(pt2tp, tags);
+ } else {
+ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
+ }
+
+ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
+ data, dev->param.total_bytes_per_chunk,
+ (dev->param.inband_tags) ? NULL : packed_tags_ptr,
+ (dev->param.inband_tags) ? 0 : packed_tags_size);
+
+ return retval;
+}
+
+static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
+ int nand_chunk, u8 *data,
+ struct yaffs_ext_tags *tags)
+{
+ int retval = 0;
+ int local_data = 0;
+ u8 spare_buffer[100];
+ enum yaffs_ecc_result ecc_result;
+
+ struct yaffs_packed_tags2 pt;
+
+ int packed_tags_size =
+ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
+ void *packed_tags_ptr =
+ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
+
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "yaffs_tags_marshall_read chunk %d data %p tags %p",
+ nand_chunk, data, tags);
+
+ if (dev->param.inband_tags) {
+ if (!data) {
+ local_data = 1;
+ data = yaffs_get_temp_buffer(dev);
+ }
+ }
+
+ if (dev->param.inband_tags || (data && !tags))
+ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+ data, dev->param.total_bytes_per_chunk,
+ NULL, 0,
+ &ecc_result);
+ else if (tags)
+ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+ data, dev->param.total_bytes_per_chunk,
+ spare_buffer, packed_tags_size,
+ &ecc_result);
+ else
+ BUG();
+
+
+ if (dev->param.inband_tags) {
+ if (tags) {
+ struct yaffs_packed_tags2_tags_only *pt2tp;
+ pt2tp =
+ (struct yaffs_packed_tags2_tags_only *)
+ &data[dev->data_bytes_per_chunk];
+ yaffs_unpack_tags2_tags_only(tags, pt2tp);
+ }
+ } else if (tags) {
+ memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
+ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
+ }
+
+ if (local_data)
+ yaffs_release_temp_buffer(dev, data);
+
+ if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
+ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+ dev->n_ecc_unfixed++;
+ }
+
+ if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
+ if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
+ tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
+ dev->n_ecc_fixed++;
+ }
+
+ if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number)
+{
+ int retval;
+
+ yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
+ block_no);
+
+ retval = dev->drv.drv_check_bad_fn(dev, block_no);
+
+ if (retval== YAFFS_FAIL) {
+ yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
+
+ *state = YAFFS_BLOCK_STATE_DEAD;
+ *seq_number = 0;
+ } else {
+ struct yaffs_ext_tags t;
+
+ yaffs_tags_marshall_read(dev,
+ block_no * dev->param.chunks_per_block,
+ NULL, &t);
+
+ if (t.chunk_used) {
+ *seq_number = t.seq_number;
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+ } else {
+ *seq_number = 0;
+ *state = YAFFS_BLOCK_STATE_EMPTY;
+ }
+ }
+
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "block query returns seq %d state %d",
+ *seq_number, *state);
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+ return dev->drv.drv_mark_bad_fn(dev, block_no);
+
+}
+
+
+void yaffs_tags_marshall_install(struct yaffs_dev *dev)
+{
+ if (!dev->param.is_yaffs2)
+ return;
+
+ if (!dev->tagger.write_chunk_tags_fn)
+ dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
+
+ if (!dev->tagger.read_chunk_tags_fn)
+ dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
+
+ if (!dev->tagger.query_block_fn)
+ dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
+
+ if (!dev->tagger.mark_bad_fn)
+ dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
+
+}
/*
- * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
-
-#ifndef __YAFFS_NOR_IF1_H__
-#define __YAFFS_NOR_IF1_H__
+#ifndef __YAFFS_TAGSMARSHALL_H__
+#define __YAFFS_TAGSMARSHALL_H__
#include "yaffs_guts.h"
-
-int ynorif1_WriteChunkToNAND(struct yaffs_dev *dev,int nand_chunk,const u8 *data, const struct yaffs_spare *spare);
-int ynorif1_ReadChunkFromNAND(struct yaffs_dev *dev,int nand_chunk, u8 *data, struct yaffs_spare *spare);
-int ynorif1_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
-int ynorif1_InitialiseNAND(struct yaffs_dev *dev);
-int ynorif1_Deinitialise_flash_fn(struct yaffs_dev *dev);
+void yaffs_tags_marshall_install(struct yaffs_dev *dev);
#endif
-
-
#include "yaffs_linux.h"
#include "yaffs_mtdif.h"
-#include "yaffs_mtdif1.h"
-#include "yaffs_mtdif2.h"
unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
static void yaffs_put_super(struct super_block *sb)
{
struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
- yaffs_trace(YAFFS_TRACE_OS, "yaffs_put_super");
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
+ "yaffs_put_super");
yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
"Shutting down yaffs background thread");
yaffs_flush_super(sb, 1);
- if (yaffs_dev_to_lc(dev)->put_super_fn)
- yaffs_dev_to_lc(dev)->put_super_fn(sb);
-
yaffs_deinitialise(dev);
yaffs_gross_unlock(dev);
}
kfree(dev);
-}
-
-static void yaffs_mtd_put_super(struct super_block *sb)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_super_to_dev(sb));
- if (mtd->sync)
+ if (mtd && mtd->sync)
mtd->sync(mtd);
- put_mtd_device(mtd);
+ if(mtd)
+ put_mtd_device(mtd);
+
+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
+ "yaffs_put_super done");
}
+
static void yaffs_touch_super(struct yaffs_dev *dev)
{
struct super_block *sb = yaffs_dev_to_lc(dev)->super;
/* Set up the memory size parameters.... */
- n_blocks =
- YCALCBLOCKS(mtd->size,
- (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
- param->start_block = 0;
- param->end_block = n_blocks - 1;
- param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
- param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
param->n_reserved_blocks = 5;
param->n_caches = (options.no_cache) ? 0 : 10;
param->inband_tags = options.inband_tags;
/* ... and the functions. */
if (yaffs_version == 2) {
- param->write_chunk_tags_fn = nandmtd2_write_chunk_tags;
- param->read_chunk_tags_fn = nandmtd2_read_chunk_tags;
- param->bad_block_fn = nandmtd2_mark_block_bad;
- param->query_block_fn = nandmtd2_query_block;
- yaffs_dev_to_lc(dev)->spare_buffer =
- kmalloc(mtd->oobsize, GFP_NOFS);
param->is_yaffs2 = 1;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
param->total_bytes_per_chunk = mtd->writesize;
param->start_block = 0;
param->end_block = n_blocks - 1;
} else {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
- /* use the MTD interface in yaffs_mtdif1.c */
- param->write_chunk_tags_fn = nandmtd1_write_chunk_tags;
- param->read_chunk_tags_fn = nandmtd1_read_chunk_tags;
- param->bad_block_fn = nandmtd1_mark_block_bad;
- param->query_block_fn = nandmtd1_query_block;
-#else
- param->write_chunk_fn = nandmtd_write_chunk;
- param->read_chunk_fn = nandmtd_read_chunk;
-#endif
param->is_yaffs2 = 0;
+ n_blocks = YCALCBLOCKS(mtd->size,
+ YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
+
+ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
+ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
}
- /* ... and common functions */
- param->erase_fn = nandmtd_erase_block;
- param->initialise_flash_fn = nandmtd_initialise;
- yaffs_dev_to_lc(dev)->put_super_fn = yaffs_mtd_put_super;
+ param->start_block = 0;
+ param->end_block = n_blocks - 1;
+
+ yaffs_mtd_drv_install(dev);
param->sb_dirty_fn = yaffs_touch_super;
- param->gc_control = yaffs_gc_control_callback;
+ param->gc_control_fn = yaffs_gc_control_callback;
yaffs_dev_to_lc(dev)->super = sb;
static void yaffs_put_super(struct super_block *sb)
{
struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
yaffs_trace(YAFFS_TRACE_OS, "yaffs_put_super");
}
kfree(dev);
-}
-static void yaffs_mtd_put_super(struct super_block *sb)
-{
- struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_super_to_dev(sb));
- if (mtd->sync)
+
+ if (mtd && mtd->sync)
mtd->sync(mtd);
- put_mtd_device(mtd);
+ if (mtd)
+ put_mtd_device(mtd);
}
static const struct super_operations yaffs_super_ops = {
yaffs_dev_to_lc(dev)->put_super_fn = yaffs_mtd_put_super;
param->sb_dirty_fn = yaffs_touch_super;
- param->gc_control = yaffs_gc_control_callback;
+ param->gc_control_fn = yaffs_gc_control_callback;
yaffs_dev_to_lc(dev)->super = sb;