Patchwork MTD: Add nand_ecc test module

login
register
mail settings
Submitter Akinobu Mita
Date Oct. 9, 2009, 9:54 a.m.
Message ID <1255082095-22158-1-git-send-email-akinobu.mita@gmail.com>
Download mbox | patch
Permalink /patch/35608/
State New, archived
Headers show

Comments

Akinobu Mita - Oct. 9, 2009, 9:54 a.m.
This module tests NAND ECC functions.

The test is simple.

1. Create a 256 or 512 bytes block of data filled with random bytes (data)
2. Duplicate the data block and inject single bit error (error_data)
3. Try to correct error_data
4. Compare data and error_data

If the test fails, this creates create these files in debugfs:

/sys/kernel/debug/nand-ecc-test-crashers/

        <testname>
        <testname>-error

<testname> contains data
<testname>-error contains error_data

Cc: David Woodhouse <dwmw2@infradead.org>
Cc: linux-mtd@lists.infradead.org
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
 drivers/mtd/nand/nand_ecc.c       |   25 ++++-
 drivers/mtd/tests/Makefile        |    1 +
 drivers/mtd/tests/nand_ecc-test.c |  200 +++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nand_ecc.h      |    6 +
 4 files changed, 227 insertions(+), 5 deletions(-)
 create mode 100644 drivers/mtd/tests/nand_ecc-test.c
Artem Bityutskiy - Oct. 11, 2009, 1:39 p.m.
On Fri, 2009-10-09 at 18:54 +0900, Akinobu Mita wrote:
> This module tests NAND ECC functions.
> 
> The test is simple.
> 
> 1. Create a 256 or 512 bytes block of data filled with random bytes (data)
> 2. Duplicate the data block and inject single bit error (error_data)
> 3. Try to correct error_data
> 4. Compare data and error_data

So you want to test the built-in 256/512 software ECC calculation
and correction functions?

> If the test fails, this creates create these files in debugfs:
> 
> /sys/kernel/debug/nand-ecc-test-crashers/
> 
>         <testname>
>         <testname>-error
> 
> <testname> contains data
> <testname>-error contains error_data

Why you need these files? This looks like overkill. Please, remove
them.

> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: linux-mtd@lists.infradead.org
> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
> ---
>  drivers/mtd/nand/nand_ecc.c       |   25 ++++-
>  drivers/mtd/tests/Makefile        |    1 +
>  drivers/mtd/tests/nand_ecc-test.c |  200 +++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/nand_ecc.h      |    6 +
>  4 files changed, 227 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/mtd/tests/nand_ecc-test.c

Could you please split this on 2 patches - one is changing the generic
code, one is the test itself.

> 
> diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
> index db7ae9d..809fb53 100644
> --- a/drivers/mtd/nand/nand_ecc.c
> +++ b/drivers/mtd/nand/nand_ecc.c
> @@ -150,20 +150,19 @@ static const char addressbits[256] = {
>  };
>  
>  /**
> - * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
> + * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
>   *			 block
> - * @mtd:	MTD block structure
>   * @buf:	input buffer with raw data
> + * @eccsize:	data bytes per ecc step (256 or 512)
>   * @code:	output buffer with ECC
>   */
> -int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
> +void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
>  		       unsigned char *code)
>  {
>  	int i;
>  	const uint32_t *bp = (uint32_t *)buf;
>  	/* 256 or 512 bytes/ecc  */
> -	const uint32_t eccsize_mult =
> -			(((struct nand_chip *)mtd->priv)->ecc.size) >> 8;
> +	const uint32_t eccsize_mult = eccsize >> 8;
>  	uint32_t cur;		/* current value in buffer */
>  	/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
>  	uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
> @@ -412,6 +411,22 @@ int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
>  		    (invparity[par & 0x55] << 2) |
>  		    (invparity[rp17] << 1) |
>  		    (invparity[rp16] << 0);
> +}
> +EXPORT_SYMBOL(__nand_calculate_ecc);
> +
> +/**
> + * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
> + *			 block
> + * @mtd:	MTD block structure
> + * @buf:	input buffer with raw data
> + * @code:	output buffer with ECC
> + */
> +int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
> +		       unsigned char *code)
> +{
> +	__nand_calculate_ecc(buf,
> +			((struct nand_chip *)mtd->priv)->ecc.size, code);
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL(nand_calculate_ecc);
> diff --git a/drivers/mtd/tests/Makefile b/drivers/mtd/tests/Makefile
> index c1d5013..0c23b29 100644
> --- a/drivers/mtd/tests/Makefile
> +++ b/drivers/mtd/tests/Makefile
> @@ -5,3 +5,4 @@ obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o
>  obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o
>  obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o
>  obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
> +obj-$(CONFIG_MTD_TESTS) += nand_ecc-test.o
> diff --git a/drivers/mtd/tests/nand_ecc-test.c b/drivers/mtd/tests/nand_ecc-test.c
> new file mode 100644
> index 0000000..143630c
> --- /dev/null
> +++ b/drivers/mtd/tests/nand_ecc-test.c
> @@ -0,0 +1,200 @@
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/debugfs.h>
> +#include <linux/list.h>
> +#include <linux/slab.h>
> +#include <linux/random.h>
> +#include <linux/string.h>
> +#include <linux/bitops.h>
> +#include <linux/jiffies.h>
> +
> +void inject_single_bit_error(void *data, size_t size)
> +{
> +	unsigned long offset = random32() % (size * BITS_PER_BYTE);
> +
> +	__change_bit(offset, data);
> +}
> +
> +static struct dentry *ecc_test_dir;
> +
> +struct ecc_test_blob {
> +	struct dentry *dir;
> +	struct debugfs_blob_wrapper blob;
> +};
> +
> +static struct ecc_test_blob *create_ecc_test_blob(const char *name, void *data,
> +						size_t size)
> +{
> +	struct ecc_test_blob *blob;
> +
> +	blob = kmalloc(sizeof(*blob), GFP_KERNEL);
> +	if (!blob)
> +		return NULL;
> +
> +	blob->blob.size = size;
> +	blob->blob.data = kmemdup(data, size, GFP_KERNEL);
> +	if (!blob->blob.data)
> +		goto err1;
> +
> +	blob->dir = debugfs_create_blob(name, S_IRUSR, ecc_test_dir,
> +						&blob->blob);
> +	if (!blob->dir)
> +		goto err2;
> +
> +	return blob;
> +err2:
> +	kfree(blob->blob.data);
> +err1:
> +	kfree(blob);
> +
> +	return NULL;
> +}
> +
> +static void remove_ecc_test_blob(struct ecc_test_blob *blob)
> +{
> +	debugfs_remove(blob->dir);
> +	kfree(blob->blob.data);
> +	kfree(blob);
> +}
> +
> +static LIST_HEAD(ecc_test_crashers);
> +
> +struct ecc_test_crasher {
> +	struct list_head list;
> +
> +	struct ecc_test_blob *data;
> +	struct ecc_test_blob *error_data;
> +};
> +
> +/*
> + * Create these files in debugfs:
> + *
> + * /sys/kernel/debug/nand-ecc-test-crashers/
> + *	<name>		binary blob specified with data
> + *	<name>-error	binary blob specified with error_data
> + */
> +static int register_ecc_test_crasher(const char *name, void *data,
> +				void *error_data, size_t size)
> +{
> +	struct ecc_test_crasher *crasher;
> +	char *error_name;
> +
> +	crasher = kmalloc(sizeof(*crasher), GFP_KERNEL);
> +	if (!crasher)
> +		return -ENOMEM;
> +
> +	crasher->data = create_ecc_test_blob(name, data, size);
> +	if (!crasher->data)
> +		goto err1;
> +
> +	error_name = kasprintf(GFP_KERNEL, "%s-error", name);
> +	if (!error_name)
> +		goto err2;
> +
> +	crasher->error_data = create_ecc_test_blob(error_name, error_data,
> +							size);
> +	kfree(error_name);
> +
> +	if (!crasher->error_data)
> +		goto err3;
> +
> +	list_add(&crasher->list, &ecc_test_crashers);
> +
> +	return 0;
> +err3:
> +	remove_ecc_test_blob(crasher->error_data);
> +err2:
> +	remove_ecc_test_blob(crasher->data);
> +err1:
> +	kfree(crasher);
> +
> +	return -ENOMEM;
> +}
> +
> +static void unregister_ecc_test_crasher(struct ecc_test_crasher *crasher)
> +{
> +	list_del(&crasher->list);
> +
> +	remove_ecc_test_blob(crasher->error_data);
> +	remove_ecc_test_blob(crasher->data);
> +	kfree(crasher);
> +}
> +
> +#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)

This should not be needed. MTD tests are always compiled as modules,
so you should not have copilation errors. And if MTD NAND support is
not present, modprobe will just fail.
Akinobu Mita - Oct. 13, 2009, 9:58 a.m.
On Sun, Oct 11, 2009 at 04:39:41PM +0300, Artem Bityutskiy wrote:
> On Fri, 2009-10-09 at 18:54 +0900, Akinobu Mita wrote:
> > This module tests NAND ECC functions.
> > 
> > The test is simple.
> > 
> > 1. Create a 256 or 512 bytes block of data filled with random bytes (data)
> > 2. Duplicate the data block and inject single bit error (error_data)
> > 3. Try to correct error_data
> > 4. Compare data and error_data
> 
> So you want to test the built-in 256/512 software ECC calculation
> and correction functions?

Yes.

> > If the test fails, this creates create these files in debugfs:
> > 
> > /sys/kernel/debug/nand-ecc-test-crashers/
> > 
> >         <testname>
> >         <testname>-error
> > 
> > <testname> contains data
> > <testname>-error contains error_data
> 
> Why you need these files? This looks like overkill. Please, remove
> them.

OK. I'll remove them and just do hexdump() if the test fails.

> > Cc: David Woodhouse <dwmw2@infradead.org>
> > Cc: linux-mtd@lists.infradead.org
> > Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
> > ---
> >  drivers/mtd/nand/nand_ecc.c       |   25 ++++-
> >  drivers/mtd/tests/Makefile        |    1 +
> >  drivers/mtd/tests/nand_ecc-test.c |  200 +++++++++++++++++++++++++++++++++++++
> >  include/linux/mtd/nand_ecc.h      |    6 +
> >  4 files changed, 227 insertions(+), 5 deletions(-)
> >  create mode 100644 drivers/mtd/tests/nand_ecc-test.c
> 
> Could you please split this on 2 patches - one is changing the generic
> code, one is the test itself.

OK.

...

> > +static void unregister_ecc_test_crasher(struct ecc_test_crasher *crasher)
> > +{
> > +	list_del(&crasher->list);
> > +
> > +	remove_ecc_test_blob(crasher->error_data);
> > +	remove_ecc_test_blob(crasher->data);
> > +	kfree(crasher);
> > +}
> > +
> > +#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)
> 
> This should not be needed. MTD tests are always compiled as modules,
> so you should not have copilation errors. And if MTD NAND support is
> not present, modprobe will just fail.

nand_calculate_ecc and nand_correct_data needs CONFIG_MTD_NAND=y|m,
otherwise it will get link error:

ERROR: "__nand_correct_data" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
ERROR: "__nand_calculate_ecc" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
Artem Bityutskiy - Oct. 14, 2009, 3:41 p.m.
On Tue, 2009-10-13 at 18:58 +0900, Akinobu Mita wrote:
> > This should not be needed. MTD tests are always compiled as modules,
> > so you should not have copilation errors. And if MTD NAND support is
> > not present, modprobe will just fail.
> 
> nand_calculate_ecc and nand_correct_data needs CONFIG_MTD_NAND=y|m,
> otherwise it will get link error:
> 
> ERROR: "__nand_correct_data" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
> ERROR: "__nand_calculate_ecc" [drivers/mtd/tests/nand_ecc-test.ko] undefined!

How about splitting tests on 2 parts - one part which does not require
NAND, and one which does, and make the second part compile only if NAND
is enabled ("depends" operator in Kconfig) ?
vimal singh - Oct. 15, 2009, 5:05 a.m.
On Wed, Oct 14, 2009 at 9:11 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> On Tue, 2009-10-13 at 18:58 +0900, Akinobu Mita wrote:
>> > This should not be needed. MTD tests are always compiled as modules,
>> > so you should not have copilation errors. And if MTD NAND support is
>> > not present, modprobe will just fail.
>>
>> nand_calculate_ecc and nand_correct_data needs CONFIG_MTD_NAND=y|m,
>> otherwise it will get link error:
>>
>> ERROR: "__nand_correct_data" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
>> ERROR: "__nand_calculate_ecc" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
>
> How about splitting tests on 2 parts - one part which does not require
> NAND, and one which does, and make the second part compile only if NAND
> is enabled ("depends" operator in Kconfig) ?

I thought purpose of this test was to test correctness of
'nand_calculate_ecc' and 'nand_correct_data' functions (i.e. algos),
which are only compiled and available when NAND is enabled.

-vimal

>
> --
> Best Regards,
> Artem Bityutskiy (Артём Битюцкий)
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>
Artem Bityutskiy - Oct. 15, 2009, 6:36 a.m.
On Thu, 2009-10-15 at 10:35 +0530, vimal singh wrote:
> On Wed, Oct 14, 2009 at 9:11 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> > On Tue, 2009-10-13 at 18:58 +0900, Akinobu Mita wrote:
> >> > This should not be needed. MTD tests are always compiled as modules,
> >> > so you should not have copilation errors. And if MTD NAND support is
> >> > not present, modprobe will just fail.
> >>
> >> nand_calculate_ecc and nand_correct_data needs CONFIG_MTD_NAND=y|m,
> >> otherwise it will get link error:
> >>
> >> ERROR: "__nand_correct_data" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
> >> ERROR: "__nand_calculate_ecc" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
> >
> > How about splitting tests on 2 parts - one part which does not require
> > NAND, and one which does, and make the second part compile only if NAND
> > is enabled ("depends" operator in Kconfig) ?
> 
> I thought purpose of this test was to test correctness of
> 'nand_calculate_ecc' and 'nand_correct_data' functions (i.e. algos),
> which are only compiled and available when NAND is enabled.

That is exactly what I meant as well.
vimal singh - Oct. 15, 2009, 6:42 a.m.
On Thu, Oct 15, 2009 at 12:06 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> On Thu, 2009-10-15 at 10:35 +0530, vimal singh wrote:
>> On Wed, Oct 14, 2009 at 9:11 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
>> > On Tue, 2009-10-13 at 18:58 +0900, Akinobu Mita wrote:
>> >> > This should not be needed. MTD tests are always compiled as modules,
>> >> > so you should not have copilation errors. And if MTD NAND support is
>> >> > not present, modprobe will just fail.
>> >>
>> >> nand_calculate_ecc and nand_correct_data needs CONFIG_MTD_NAND=y|m,
>> >> otherwise it will get link error:
>> >>
>> >> ERROR: "__nand_correct_data" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
>> >> ERROR: "__nand_calculate_ecc" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
>> >
>> > How about splitting tests on 2 parts - one part which does not require
>> > NAND, and one which does, and make the second part compile only if NAND
>> > is enabled ("depends" operator in Kconfig) ?
>>
>> I thought purpose of this test was to test correctness of
>> 'nand_calculate_ecc' and 'nand_correct_data' functions (i.e. algos),
>> which are only compiled and available when NAND is enabled.
>
> That is exactly what I meant as well.

Then, what do you meant to test in first part of test. Sorry if I am
misinterpreting you statement above.
Artem Bityutskiy - Oct. 15, 2009, 6:50 a.m.
On Thu, 2009-10-15 at 12:12 +0530, vimal singh wrote:
> On Thu, Oct 15, 2009 at 12:06 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> > On Thu, 2009-10-15 at 10:35 +0530, vimal singh wrote:
> >> On Wed, Oct 14, 2009 at 9:11 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> >> > On Tue, 2009-10-13 at 18:58 +0900, Akinobu Mita wrote:
> >> >> > This should not be needed. MTD tests are always compiled as modules,
> >> >> > so you should not have copilation errors. And if MTD NAND support is
> >> >> > not present, modprobe will just fail.
> >> >>
> >> >> nand_calculate_ecc and nand_correct_data needs CONFIG_MTD_NAND=y|m,
> >> >> otherwise it will get link error:
> >> >>
> >> >> ERROR: "__nand_correct_data" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
> >> >> ERROR: "__nand_calculate_ecc" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
> >> >
> >> > How about splitting tests on 2 parts - one part which does not require
> >> > NAND, and one which does, and make the second part compile only if NAND
> >> > is enabled ("depends" operator in Kconfig) ?
> >>
> >> I thought purpose of this test was to test correctness of
> >> 'nand_calculate_ecc' and 'nand_correct_data' functions (i.e. algos),
> >> which are only compiled and available when NAND is enabled.
> >
> > That is exactly what I meant as well.
> 
> Then, what do you meant to test in first part of test. Sorry if I am
> misinterpreting you statement above.

May be this is me who is misunderstanding. We have tests which work fine
with both NOR and NAND. But some tests work only on NOR. E.g., the
subpage test. We did not have _compile_ dependencies, so it was not a
problem. NAND-only tests just returned on !NANDs.

This new test requeres NAND support to be compiled.

So what I suggested, is to split the tests on 2 groups on the Kconfig
level, and make the NAND-only group depend on NAND support. This will
make them be compiled only if NAND support is there. Then this new test
will be part of the NAND-only group.

I'm not 100% sure this is nice approach, though. But #ifdef NAND things
in the test are ugly, IMO.
vimal singh - Oct. 15, 2009, 8:53 a.m.
On Thu, Oct 15, 2009 at 12:20 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> On Thu, 2009-10-15 at 12:12 +0530, vimal singh wrote:
>> On Thu, Oct 15, 2009 at 12:06 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
>> > On Thu, 2009-10-15 at 10:35 +0530, vimal singh wrote:
>> >> On Wed, Oct 14, 2009 at 9:11 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
>> >> > On Tue, 2009-10-13 at 18:58 +0900, Akinobu Mita wrote:
>> >> >> > This should not be needed. MTD tests are always compiled as modules,
>> >> >> > so you should not have copilation errors. And if MTD NAND support is
>> >> >> > not present, modprobe will just fail.
>> >> >>
>> >> >> nand_calculate_ecc and nand_correct_data needs CONFIG_MTD_NAND=y|m,
>> >> >> otherwise it will get link error:
>> >> >>
>> >> >> ERROR: "__nand_correct_data" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
>> >> >> ERROR: "__nand_calculate_ecc" [drivers/mtd/tests/nand_ecc-test.ko] undefined!
>> >> >
>> >> > How about splitting tests on 2 parts - one part which does not require
>> >> > NAND, and one which does, and make the second part compile only if NAND
>> >> > is enabled ("depends" operator in Kconfig) ?
>> >>
>> >> I thought purpose of this test was to test correctness of
>> >> 'nand_calculate_ecc' and 'nand_correct_data' functions (i.e. algos),
>> >> which are only compiled and available when NAND is enabled.
>> >
>> > That is exactly what I meant as well.
>>
>> Then, what do you meant to test in first part of test. Sorry if I am
>> misinterpreting you statement above.
>
> May be this is me who is misunderstanding. We have tests which work fine
> with both NOR and NAND. But some tests work only on NOR. E.g., the
> subpage test. We did not have _compile_ dependencies, so it was not a
> problem. NAND-only tests just returned on !NANDs.
>
> This new test requeres NAND support to be compiled.
>
> So what I suggested, is to split the tests on 2 groups on the Kconfig
> level, and make the NAND-only group depend on NAND support. This will
> make them be compiled only if NAND support is there. Then this new test
> will be part of the NAND-only group.
>
> I'm not 100% sure this is nice approach, though. But #ifdef NAND things
> in the test are ugly, IMO.

To me this approach looks fine. I do have seen that oobtest test
(scenario 4) does not holds good for NAND parts. Since NAND driver
allows to read past the page.

Patch

diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index db7ae9d..809fb53 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -150,20 +150,19 @@  static const char addressbits[256] = {
 };
 
 /**
- * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+ * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
  *			 block
- * @mtd:	MTD block structure
  * @buf:	input buffer with raw data
+ * @eccsize:	data bytes per ecc step (256 or 512)
  * @code:	output buffer with ECC
  */
-int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
 		       unsigned char *code)
 {
 	int i;
 	const uint32_t *bp = (uint32_t *)buf;
 	/* 256 or 512 bytes/ecc  */
-	const uint32_t eccsize_mult =
-			(((struct nand_chip *)mtd->priv)->ecc.size) >> 8;
+	const uint32_t eccsize_mult = eccsize >> 8;
 	uint32_t cur;		/* current value in buffer */
 	/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
 	uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
@@ -412,6 +411,22 @@  int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
 		    (invparity[par & 0x55] << 2) |
 		    (invparity[rp17] << 1) |
 		    (invparity[rp16] << 0);
+}
+EXPORT_SYMBOL(__nand_calculate_ecc);
+
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+ *			 block
+ * @mtd:	MTD block structure
+ * @buf:	input buffer with raw data
+ * @code:	output buffer with ECC
+ */
+int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+		       unsigned char *code)
+{
+	__nand_calculate_ecc(buf,
+			((struct nand_chip *)mtd->priv)->ecc.size, code);
+
 	return 0;
 }
 EXPORT_SYMBOL(nand_calculate_ecc);
diff --git a/drivers/mtd/tests/Makefile b/drivers/mtd/tests/Makefile
index c1d5013..0c23b29 100644
--- a/drivers/mtd/tests/Makefile
+++ b/drivers/mtd/tests/Makefile
@@ -5,3 +5,4 @@  obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
+obj-$(CONFIG_MTD_TESTS) += nand_ecc-test.o
diff --git a/drivers/mtd/tests/nand_ecc-test.c b/drivers/mtd/tests/nand_ecc-test.c
new file mode 100644
index 0000000..143630c
--- /dev/null
+++ b/drivers/mtd/tests/nand_ecc-test.c
@@ -0,0 +1,200 @@ 
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+
+void inject_single_bit_error(void *data, size_t size)
+{
+	unsigned long offset = random32() % (size * BITS_PER_BYTE);
+
+	__change_bit(offset, data);
+}
+
+static struct dentry *ecc_test_dir;
+
+struct ecc_test_blob {
+	struct dentry *dir;
+	struct debugfs_blob_wrapper blob;
+};
+
+static struct ecc_test_blob *create_ecc_test_blob(const char *name, void *data,
+						size_t size)
+{
+	struct ecc_test_blob *blob;
+
+	blob = kmalloc(sizeof(*blob), GFP_KERNEL);
+	if (!blob)
+		return NULL;
+
+	blob->blob.size = size;
+	blob->blob.data = kmemdup(data, size, GFP_KERNEL);
+	if (!blob->blob.data)
+		goto err1;
+
+	blob->dir = debugfs_create_blob(name, S_IRUSR, ecc_test_dir,
+						&blob->blob);
+	if (!blob->dir)
+		goto err2;
+
+	return blob;
+err2:
+	kfree(blob->blob.data);
+err1:
+	kfree(blob);
+
+	return NULL;
+}
+
+static void remove_ecc_test_blob(struct ecc_test_blob *blob)
+{
+	debugfs_remove(blob->dir);
+	kfree(blob->blob.data);
+	kfree(blob);
+}
+
+static LIST_HEAD(ecc_test_crashers);
+
+struct ecc_test_crasher {
+	struct list_head list;
+
+	struct ecc_test_blob *data;
+	struct ecc_test_blob *error_data;
+};
+
+/*
+ * Create these files in debugfs:
+ *
+ * /sys/kernel/debug/nand-ecc-test-crashers/
+ *	<name>		binary blob specified with data
+ *	<name>-error	binary blob specified with error_data
+ */
+static int register_ecc_test_crasher(const char *name, void *data,
+				void *error_data, size_t size)
+{
+	struct ecc_test_crasher *crasher;
+	char *error_name;
+
+	crasher = kmalloc(sizeof(*crasher), GFP_KERNEL);
+	if (!crasher)
+		return -ENOMEM;
+
+	crasher->data = create_ecc_test_blob(name, data, size);
+	if (!crasher->data)
+		goto err1;
+
+	error_name = kasprintf(GFP_KERNEL, "%s-error", name);
+	if (!error_name)
+		goto err2;
+
+	crasher->error_data = create_ecc_test_blob(error_name, error_data,
+							size);
+	kfree(error_name);
+
+	if (!crasher->error_data)
+		goto err3;
+
+	list_add(&crasher->list, &ecc_test_crashers);
+
+	return 0;
+err3:
+	remove_ecc_test_blob(crasher->error_data);
+err2:
+	remove_ecc_test_blob(crasher->data);
+err1:
+	kfree(crasher);
+
+	return -ENOMEM;
+}
+
+static void unregister_ecc_test_crasher(struct ecc_test_crasher *crasher)
+{
+	list_del(&crasher->list);
+
+	remove_ecc_test_blob(crasher->error_data);
+	remove_ecc_test_blob(crasher->data);
+	kfree(crasher);
+}
+
+#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)
+
+#include <linux/mtd/nand_ecc.h>
+
+static unsigned char data[512];
+static unsigned char error_data[512];
+
+static int nand_ecc_test(const size_t size)
+{
+	unsigned char code[3];
+	unsigned char error_code[3];
+	char testname[30];
+
+	BUG_ON(sizeof(data) < size);
+
+	sprintf(testname, "nand-ecc-%zu", size);
+
+	get_random_bytes(data, size);
+
+	memcpy(error_data, data, size);
+	inject_single_bit_error(error_data, size);
+
+	__nand_calculate_ecc(data, size, code);
+	__nand_calculate_ecc(error_data, size, error_code);
+	__nand_correct_data(error_data, code, error_code, size);
+
+	if (!memcmp(data, error_data, size)) {
+		printk(KERN_INFO "nand_ecc-test: ok - %s\n", testname);
+		return 0;
+	}
+
+	printk(KERN_ERR "nand_ecc-test: not ok - %s\n", testname);
+	register_ecc_test_crasher(testname, data, error_data, size);
+
+	return -1;
+}
+
+#else
+
+static int nand_ecc_test(const size_t size)
+{
+	return 0;
+}
+
+#endif
+
+static int __init ecc_test_init(void)
+{
+	srandom32(jiffies);
+
+	ecc_test_dir = debugfs_create_dir("nand-ecc-test-crashers", NULL);
+	if (!ecc_test_dir)
+		return -ENOMEM;
+
+	nand_ecc_test(256);
+	nand_ecc_test(512);
+
+	return 0;
+}
+
+static void __exit ecc_test_exit(void)
+{
+	while (!list_empty(&ecc_test_crashers)) {
+		struct ecc_test_crasher *crasher;
+
+		crasher = list_first_entry(&ecc_test_crashers,
+					struct ecc_test_crasher, list);
+		unregister_ecc_test_crasher(crasher);
+	}
+	debugfs_remove_recursive(ecc_test_dir);
+}
+
+module_init(ecc_test_init);
+module_exit(ecc_test_exit);
+
+MODULE_DESCRIPTION("ECC test module");
+MODULE_AUTHOR("Akinobu Mita");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h
index 052ea8c..9cb10ff 100644
--- a/include/linux/mtd/nand_ecc.h
+++ b/include/linux/mtd/nand_ecc.h
@@ -16,6 +16,12 @@ 
 struct mtd_info;
 
 /*
+ * Calculate 3 byte ECC code for eccsize byte block
+ */
+void __nand_calculate_ecc(const u_char *dat, unsigned int eccsize,
+				u_char *ecc_code);
+
+/*
  * Calculate 3 byte ECC code for 256 byte block
  */
 int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);