All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ryan Mallon <ryan@bluewatersys.com>
To: Charles Manning <cdhmanning@gmail.com>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	akpm@linux-foundation.org
Subject: Re: [PATCH 04/10] Add yaffs2 file system: Flash interfacing and ECC handling code
Date: Thu, 20 Jan 2011 12:27:42 +1300	[thread overview]
Message-ID: <4D37736E.2080605@bluewatersys.com> (raw)
In-Reply-To: <1294974369-31647-5-git-send-email-cdhmanning@gmail.com>

cOn 01/14/2011 04:06 PM, Charles Manning wrote:
> Signed-off-by: Charles Manning <cdhmanning@gmail.com>

Hi Charles,

Is it possible to make features like yaffs doing its own ecc, ecc wrong
order and 9 byte tags mount options? It would reduce the number of
Kconfig options and the amount of ifdefery in these files.

More comments below.

~Ryan

> ---
>  fs/yaffs2/yaffs_ecc.c    |  296 +++++++++++++++++++++++++++++++++++++++++
>  fs/yaffs2/yaffs_ecc.h    |   44 ++++++
>  fs/yaffs2/yaffs_mtdif.c  |   53 ++++++++
>  fs/yaffs2/yaffs_mtdif.h  |   23 ++++
>  fs/yaffs2/yaffs_mtdif1.c |  329 ++++++++++++++++++++++++++++++++++++++++++++++
>  fs/yaffs2/yaffs_mtdif1.h |   29 ++++
>  fs/yaffs2/yaffs_mtdif2.c |  215 ++++++++++++++++++++++++++++++
>  fs/yaffs2/yaffs_mtdif2.h |   29 ++++
>  fs/yaffs2/yaffs_nand.c   |  120 +++++++++++++++++
>  fs/yaffs2/yaffs_nand.h   |   38 ++++++
>  10 files changed, 1176 insertions(+), 0 deletions(-)
>  create mode 100644 fs/yaffs2/yaffs_ecc.c
>  create mode 100644 fs/yaffs2/yaffs_ecc.h
>  create mode 100644 fs/yaffs2/yaffs_mtdif.c
>  create mode 100644 fs/yaffs2/yaffs_mtdif.h
>  create mode 100644 fs/yaffs2/yaffs_mtdif1.c
>  create mode 100644 fs/yaffs2/yaffs_mtdif1.h
>  create mode 100644 fs/yaffs2/yaffs_mtdif2.c
>  create mode 100644 fs/yaffs2/yaffs_mtdif2.h
>  create mode 100644 fs/yaffs2/yaffs_nand.c
>  create mode 100644 fs/yaffs2/yaffs_nand.h
> 
> diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c
> new file mode 100644
> index 0000000..4f29b80
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_ecc.c
> @@ -0,0 +1,296 @@
> +/*
> + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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 code implements the ECC algorithm used in SmartMedia.
> + *
> + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
> + * The two unused bit are set to 1.
> + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
> + * such ECC blocks are used on a 512-byte NAND page.
> + *
> + */
> +
> +/* Table generated by gen-ecc.c
> + * Using a table means we do not have to calculate p1..p4 and p1'..p4'
> + * for each byte of data. These are instead provided in a table in bits7..2.
> + * Bit 0 of each entry indicates whether the entry has an odd or even parity,
> + * and therefore this bytes influence on the line parity.
> + */
> +
> +#include "yportenv.h"
> +
> +#include "yaffs_ecc.h"
> +
> +static const unsigned char column_parity_table[] = {
> +	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
> +	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
> +	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
> +	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
> +	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
> +	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
> +	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
> +	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
> +	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
> +	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
> +	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
> +	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
> +	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
> +	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
> +	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
> +	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
> +	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
> +	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
> +	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
> +	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
> +	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
> +	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
> +	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
> +	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
> +	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
> +	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
> +	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
> +	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
> +	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
> +	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
> +	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
> +	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
> +};
> +
> +
> +/* Calculate the ECC for a 256-byte block of data */
> +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
> +{
> +	unsigned int i;
> +	unsigned char col_parity = 0;
> +	unsigned char line_parity = 0;
> +	unsigned char line_parity_prime = 0;
> +	unsigned char t;
> +	unsigned char b;
> +
> +	for (i = 0; i < 256; i++) {
> +		b = column_parity_table[*data++];
> +		col_parity ^= b;
> +
> +		if (b & 0x01) {	/* odd number of bits in the byte */
> +			line_parity ^= i;
> +			line_parity_prime ^= ~i;
> +		}
> +	}
> +
> +	ecc[2] = (~col_parity) | 0x03;
> +
> +	t = 0;
> +	if (line_parity & 0x80)
> +		t |= 0x80;
> +	if (line_parity_prime & 0x80)
> +		t |= 0x40;
> +	if (line_parity & 0x40)
> +		t |= 0x20;
> +	if (line_parity_prime & 0x40)
> +		t |= 0x10;
> +	if (line_parity & 0x20)
> +		t |= 0x08;
> +	if (line_parity_prime & 0x20)
> +		t |= 0x04;
> +	if (line_parity & 0x10)
> +		t |= 0x02;
> +	if (line_parity_prime & 0x10)
> +		t |= 0x01;
> +	ecc[1] = ~t;
> +
> +	t = 0;
> +	if (line_parity & 0x08)
> +		t |= 0x80;
> +	if (line_parity_prime & 0x08)
> +		t |= 0x40;
> +	if (line_parity & 0x04)
> +		t |= 0x20;
> +	if (line_parity_prime & 0x04)
> +		t |= 0x10;
> +	if (line_parity & 0x02)
> +		t |= 0x08;
> +	if (line_parity_prime & 0x02)
> +		t |= 0x04;
> +	if (line_parity & 0x01)
> +		t |= 0x02;
> +	if (line_parity_prime & 0x01)
> +		t |= 0x01;
> +	ecc[0] = ~t;
> +
> +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
> +	/* Swap the bytes into the wrong order */
> +	t = ecc[0];
> +	ecc[0] = ecc[1];
> +	ecc[1] = t;
> +#endif
> +}
> +
> +/* Correct the ECC on a 256 byte block of data */
> +
> +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
> +		      const unsigned char *test_ecc)
> +{
> +	unsigned char d0, d1, d2;	/* deltas */
> +
> +	d0 = read_ecc[0] ^ test_ecc[0];
> +	d1 = read_ecc[1] ^ test_ecc[1];
> +	d2 = read_ecc[2] ^ test_ecc[2];
> +
> +	if ((d0 | d1 | d2) == 0)
> +		return 0;	/* no error */
> +
> +	if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
> +	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
> +	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
> +		/* Single bit (recoverable) error in data */
> +
> +		unsigned byte;
> +		unsigned bit;
> +
> +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
> +		/* swap the bytes to correct for the wrong order */
> +		unsigned char t;
> +
> +		t = d0;
> +		d0 = d1;
> +		d1 = t;
> +#endif
> +
> +		bit = byte = 0;
> +
> +		if (d1 & 0x80)
> +			byte |= 0x80;
> +		if (d1 & 0x20)
> +			byte |= 0x40;
> +		if (d1 & 0x08)
> +			byte |= 0x20;
> +		if (d1 & 0x02)
> +			byte |= 0x10;
> +		if (d0 & 0x80)
> +			byte |= 0x08;
> +		if (d0 & 0x20)
> +			byte |= 0x04;
> +		if (d0 & 0x08)
> +			byte |= 0x02;
> +		if (d0 & 0x02)
> +			byte |= 0x01;
> +
> +		if (d2 & 0x80)
> +			bit |= 0x04;
> +		if (d2 & 0x20)
> +			bit |= 0x02;
> +		if (d2 & 0x08)
> +			bit |= 0x01;
> +
> +		data[byte] ^= (1 << bit);
> +
> +		return 1;	/* Corrected the error */
> +	}
> +
> +	if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
> +		/* Reccoverable error in ecc */
> +
> +		read_ecc[0] = test_ecc[0];
> +		read_ecc[1] = test_ecc[1];
> +		read_ecc[2] = test_ecc[2];
> +
> +		return 1;	/* Corrected the error */
> +	}
> +
> +	/* Unrecoverable error */
> +
> +	return -1;

errno value?

> +}
> +
> +/*
> + * ECCxxxOther does ECC calcs on arbitrary n bytes of data
> + */
> +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
> +			  struct yaffs_ecc_other *ecc_other)
> +{
> +	unsigned int i;
> +	unsigned char col_parity = 0;
> +	unsigned line_parity = 0;
> +	unsigned line_parity_prime = 0;
> +	unsigned char b;
> +
> +	for (i = 0; i < n_bytes; i++) {
> +		b = column_parity_table[*data++];
> +		col_parity ^= b;
> +
> +		if (b & 0x01) {
> +			/* odd number of bits in the byte */
> +			line_parity ^= i;
> +			line_parity_prime ^= ~i;
> +		}
> +
> +	}
> +
> +	ecc_other->col_parity = (col_parity >> 2) & 0x3f;
> +	ecc_other->line_parity = line_parity;
> +	ecc_other->line_parity_prime = line_parity_prime;
> +}
> +
> +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
> +			    struct yaffs_ecc_other *read_ecc,
> +			    const struct yaffs_ecc_other *test_ecc)
> +{
> +	unsigned char delta_col;	/* column parity delta */
> +	unsigned delta_line;	/* line parity delta */
> +	unsigned delta_line_prime;	/* line parity delta */
> +	unsigned bit;
> +
> +	delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
> +	delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
> +	delta_line_prime =
> +	    read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
> +
> +	if ((delta_col | delta_line | delta_line_prime) == 0)
> +		return 0;	/* no error */
> +
> +	if (delta_line == ~delta_line_prime &&
> +	    (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
> +		/* Single bit (recoverable) error in data */
> +
> +		bit = 0;
> +
> +		if (delta_col & 0x20)
> +			bit |= 0x04;
> +		if (delta_col & 0x08)
> +			bit |= 0x02;
> +		if (delta_col & 0x02)
> +			bit |= 0x01;
> +
> +		if (delta_line >= n_bytes)
> +			return -1;
> +
> +		data[delta_line] ^= (1 << bit);
> +
> +		return 1;	/* corrected */
> +	}
> +
> +	if ((hweight32(delta_line) +
> +	     hweight32(delta_line_prime) +
> +	     hweight8(delta_col)) == 1) {
> +		/* Reccoverable error in ecc */
> +
> +		*read_ecc = *test_ecc;
> +		return 1;	/* corrected */
> +	}
> +
> +	/* Unrecoverable error */
> +
> +	return -1;

errno value?

> +}
> diff --git a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h
> new file mode 100644
> index 0000000..a84e801
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_ecc.h
> @@ -0,0 +1,44 @@
> +/*
> + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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.
> + */
> +
> +/*
> + * This code implements the ECC algorithm used in SmartMedia.
> + *
> + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
> + * The two unused bit are set to 1.
> + * The ECC can correct single bit errors in a 256-byte page of data.
> + * Thus, two such ECC blocks are used on a 512-byte NAND page.
> + *
> + */
> +
> +#ifndef __YAFFS_ECC_H__
> +#define __YAFFS_ECC_H__
> +
> +struct yaffs_ecc_other {
> +	unsigned char col_parity;
> +	unsigned line_parity;
> +	unsigned line_parity_prime;
> +};
> +
> +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
> +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
> +		      const unsigned char *test_ecc);
> +
> +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
> +			  struct yaffs_ecc_other *ecc);
> +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
> +			    struct yaffs_ecc_other *read_ecc,
> +			    const struct yaffs_ecc_other *test_ecc);
> +#endif
> diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c
> new file mode 100644
> index 0000000..b36a8be
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_mtdif.c
> @@ -0,0 +1,53 @@
> +/*
> + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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;

Nitpick: Casts should be written like this:

	ei.prov = (u_long)dev;

This applies across the whole patch series.

> +
> +	retval = mtd->erase(mtd, &ei);
> +
> +	if (retval == 0)
> +		return YAFFS_OK;
> +	else
> +		return YAFFS_FAIL;
> +}
> +
> +int nandmtd_initialise(struct yaffs_dev *dev)
> +{
> +	return YAFFS_OK;
> +}
> diff --git a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h
> new file mode 100644
> index 0000000..6665074
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_mtdif.h
> @@ -0,0 +1,23 @@
> +/*
> + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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_MTDIF_H__
> +#define __YAFFS_MTDIF_H__
> +
> +#include "yaffs_guts.h"
> +
> +int nandmtd_erase_block(struct yaffs_dev *dev, int block_no);
> +int nandmtd_initialise(struct yaffs_dev *dev);
> +#endif
> diff --git a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c
> new file mode 100644
> index 0000000..182870c
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_mtdif1.c
> @@ -0,0 +1,329 @@
> +/*
> + * YAFFS: Yet another FFS. A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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"
> +
> +#ifndef CONFIG_YAFFS_9BYTE_TAGS
> +# define YTAG1_SIZE 8
> +#else
> +# define YTAG1_SIZE 9
> +#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);

Can use one of the BUILD_BUG_ON macros rather than rolling your own?

> +
> +	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.
> +	 */
> +#ifndef CONFIG_YAFFS_9BYTE_TAGS
> +	if (etags->is_deleted) {
> +		memset(&pt1, 0xff, 8);
> +		/* clear delete status bit to indicate deleted */
> +		pt1.deleted = 0;
> +	}
> +#else
> +	((u8 *) &pt1)[8] = 0xff;
> +	if (etags->is_deleted) {
> +		memset(&pt1, 0xff, 8);
> +		/* zero page_status byte to indicate deleted */
> +		((u8 *) &pt1)[8] = 0;
> +	}
> +#endif
> +
> +	memset(&ops, 0, sizeof(ops));
> +	ops.mode = MTD_OOB_AUTO;
> +	ops.len = (data) ? chunk_bytes : 0;
> +	ops.ooblen = YTAG1_SIZE;
> +	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;

Change this to:

	struct mtd_oob_ops ops = {0};

> +	struct yaffs_packed_tags1 pt1;
> +	int retval;
> +	int deleted;
> +
> +	memset(&ops, 0, sizeof(ops));

and then remove this memset.

> +	ops.mode = MTD_OOB_AUTO;
> +	ops.len = (data) ? chunk_bytes : 0;
> +	ops.ooblen = YTAG1_SIZE;
> +	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 mtd_info *mtd)
> +{
> +	/* 2.6.18 has mtd->ecclayout->oobavail */
> +	/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */

This comment is not applicable for mainline.

> +	int oobavail = mtd->ecclayout->oobavail;
> +
> +	if (oobavail < YTAG1_SIZE) {
> +		yaffs_trace(YAFFS_TRACE_ERROR,
> +			"mtd device has only %d bytes for tags, need %d",
> +			oobavail, YTAG1_SIZE);
> +		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_SCANNING, 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(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_SCANNING;
> +	} else if (etags.chunk_used) {
> +		state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
> +		seqnum = etags.seq_number;
> +	} else {
> +		state = YAFFS_BLOCK_STATE_EMPTY;
> +	}
> +
> +	*state_ptr = state;
> +	*seq_ptr = seqnum;
> +
> +	/* query always succeeds */
> +	return YAFFS_OK;
> +}
> diff --git a/fs/yaffs2/yaffs_mtdif1.h b/fs/yaffs2/yaffs_mtdif1.h
> new file mode 100644
> index 0000000..034c680
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_mtdif1.h
> @@ -0,0 +1,29 @@
> +/*
> + * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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
> diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
> new file mode 100644
> index 0000000..18340bd
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_mtdif2.c
> @@ -0,0 +1,215 @@
> +/*
> + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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"
> +
> +
> +/* 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;

Shouldn't need void * casts.

> +
> +	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) {

This should be a separate if statement to the one for BUG. If you don't
want fall through when BUG is not enabled, then just have:

	if (!data || !tags) {
		BUG();
		return YAFFS_FAILED;
	}

> +		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_OOB_AUTO;
> +	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;
> +	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);
> +	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;

Shouldn't need void * casts.

> +	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) {

if (dev->param.inband_tags && !data) ?

> +			local_data = 1;
> +			data = yaffs_get_temp_buffer(dev, __LINE__);
> +		}
> +	}
> +
> +	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_OOB_AUTO;
> +		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) {
> +		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, __LINE__);
> +
> +	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_SCANNING;
> +		} 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;
> +}
> +
> diff --git a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h
> new file mode 100644
> index 0000000..78babf5
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_mtdif2.h
> @@ -0,0 +1,29 @@
> +/*
> + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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
> diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
> new file mode 100644
> index 0000000..ee061a8
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_nand.c
> @@ -0,0 +1,120 @@
> +/*
> + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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_nand.h"
> +#include "yaffs_tagscompat.h"
> +#include "yaffs_tagsvalidity.h"
> +
> +#include "yaffs_getblockinfo.h"
> +
> +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 realigned_chunk = nand_chunk - dev->chunk_offset;
> +
> +	dev->n_page_reads++;
> +
> +	/* If there are no tags provided use local tags. */
> +	if (!tags)
> +		tags = &local_tags;
> +
> +	if (dev->param.read_chunk_tags_fn)
> +		result =
> +		    dev->param.read_chunk_tags_fn(dev, realigned_chunk, buffer,
> +						  tags);
> +	else
> +		result = yaffs_tags_compat_rd(dev,
> +					      realigned_chunk, buffer, tags);
> +	if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
> +
> +		struct yaffs_block_info *bi;
> +		bi = yaffs_get_block_info(dev,
> +					  nand_chunk /
> +					  dev->param.chunks_per_block);
> +		yaffs_handle_chunk_error(dev, bi);
> +	}
> +	return result;
> +}
> +
> +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
> +				int nand_chunk,
> +				const u8 *buffer, struct yaffs_ext_tags *tags)
> +{
> +	dev->n_page_writes++;
> +	nand_chunk -= dev->chunk_offset;
> +
> +	if (tags) {
> +		tags->seq_number = dev->seq_number;
> +		tags->chunk_used = 1;
> +		if (!yaffs_validate_tags(tags)) {
> +			yaffs_trace(YAFFS_TRACE_ERROR,
> +				"Writing uninitialised tags");
> +			YBUG();
> +		}
> +		yaffs_trace(YAFFS_TRACE_WRITE,
> +			"Writing chunk %d tags %d %d",
> +			nand_chunk, tags->obj_id, tags->chunk_id);
> +	} else {
> +		yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
> +		YBUG();
> +		return YAFFS_FAIL;
> +	}

I would rearrange this to make the BUG case prominent and then drop the
indentation for the case where tags is valid, ie:

	if (!tags) {
		yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
		YBUG();
		return YAFFS_FAIL;
	}

	tags->seq_number = dev->seq_number;
	...

> +
> +	if (dev->param.write_chunk_tags_fn)
> +		return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
> +							tags);
> +	else
> +		return yaffs_tags_compat_wr(dev, nand_chunk, buffer, tags);
> +}
> +
> +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);
> +	else
> +		return yaffs_tags_compat_mark_bad(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);
> +	else
> +		return yaffs_tags_compat_query_block(dev, block_no,
> +						     state, seq_number);
> +}
> +
> +int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
> +{
> +	int result;
> +
> +	flash_block -= dev->block_offset;
> +	dev->n_erasures++;
> +	result = dev->param.erase_fn(dev, flash_block);
> +	return result;

Just:
	return dev->param.erase_fn(dev, flash_block);

> +}
> +
> +int yaffs_init_nand(struct yaffs_dev *dev)
> +{
> +	if (dev->param.initialise_flash_fn)
> +		return dev->param.initialise_flash_fn(dev);
> +	return YAFFS_OK;
> +}
> diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h
> new file mode 100644
> index 0000000..a36498a
> --- /dev/null
> +++ b/fs/yaffs2/yaffs_nand.h
> @@ -0,0 +1,38 @@
> +/*
> + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
> + *
> + * Copyright (C) 2002-2010 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_NAND_H__
> +#define __YAFFS_NAND_H__
> +#include "yaffs_guts.h"
> +
> +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
> +			     u8 *buffer, struct yaffs_ext_tags *tags);
> +
> +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
> +			     int nand_chunk,
> +			     const u8 *buffer, struct yaffs_ext_tags *tags);
> +
> +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
> +
> +int yaffs_query_init_block_state(struct yaffs_dev *dev,
> +				 int block_no,
> +				 enum yaffs_block_state *state,
> +				 unsigned *seq_number);
> +
> +int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
> +
> +int yaffs_init_nand(struct yaffs_dev *dev);
> +
> +#endif


-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

  reply	other threads:[~2011-01-19 23:27 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-14  3:05 [PATCH 0/10] Add yaffs2 file system: Fourth patchset Charles Manning
2011-01-14  3:06 ` [PATCH 01/10] Add yaffs2 file system: Allocation, block handling and bitmapping code Charles Manning
2011-01-19 20:25   ` Ryan Mallon
2011-01-19 20:37     ` David Daney
2011-01-20 19:46       ` Ryan Mallon
2011-01-14  3:06 ` [PATCH 02/10] Add yaffs2 file system: Attribute and xattrib handling code Charles Manning
2011-01-19 20:37   ` Ryan Mallon
2011-01-14  3:06 ` [PATCH 03/10] Add yaffs2 file system: Checkpoint handing code Charles Manning
2011-01-19 21:47   ` Ryan Mallon
2011-01-14  3:06 ` [PATCH 04/10] Add yaffs2 file system: Flash interfacing and ECC handling code Charles Manning
2011-01-19 23:27   ` Ryan Mallon [this message]
2011-01-14  3:06 ` [PATCH 05/10] Add yaffs2 file system: Tags processing code Charles Manning
2011-01-20  0:07   ` Ryan Mallon
2011-01-14  3:06 ` [PATCH 06/10] Add yaffs2 file system: Tracing and verification code Charles Manning
2011-01-20  0:30   ` Ryan Mallon
2011-01-14  3:06 ` [PATCH 07/10] Add yaffs2 file system: yaffs1 and yaffs2 mode specific code Charles Manning
2011-01-20  4:19   ` Ryan Mallon
2011-01-14  3:06 ` [PATCH 08/10] Add yaffs2 file system: Core guts code Charles Manning
2011-01-14  3:06 ` [PATCH 09/10] Add yaffs2 file system: Linux glue code Charles Manning
2011-01-20 20:14   ` Jesper Juhl
2011-01-20 21:26   ` Ryan Mallon
2011-01-14  3:06 ` [PATCH 10/10] Add yaffs2 file system: Hook in to Linux tree Charles Manning
2011-01-20 20:32   ` Jesper Juhl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4D37736E.2080605@bluewatersys.com \
    --to=ryan@bluewatersys.com \
    --cc=akpm@linux-foundation.org \
    --cc=cdhmanning@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.