Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 10 Mar 2012 02:30:14 +0000 (UTC)
From:      Grzegorz Bernacki <gber@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r232758 - in projects/nand: share/man/man4 sys/dev/nand
Message-ID:  <201203100230.q2A2UE1a035530@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gber
Date: Sat Mar 10 02:30:14 2012
New Revision: 232758
URL: http://svn.freebsd.org/changeset/base/232758

Log:
  The FreeBSD NAND framework consists of a set of interfaces that aim to
  provide an extensible, object oriented environment for NAND controllers
  and NAND Flash memory chips from various hardware vendors, and to allow
  for uniform and flexible management of the NAND devices. It comprises of
  the following major components:
   - NAND Flash controller (NFC) interface.
           Defines methods which allow to send commands as well as send/receive
           data between the controller and a NAND chip. Back-end drivers for
           specific NAND controllers plug into this interface and implement low-
           level routines for a given NAND controller.
   - NAND chip interface.
           Provides basic operations like read page, program page, erase block.
           Currently three generic classes of drivers are available, which pro-
           vide support for the following chips: large page, small page,
           ONFI-compliant.
   - NANDbus.
           This layer is responsible for enumerating NAND chips in the system
           and establishing the hierarchy between chips and their supervising
           controllers.
   - NAND character / GEOM device.
           For each NAND chip found in a system a character and GEOM devices are
           created which allows to read / write directly to a device, as well as
           perform other specific operations (like via ioctl).
  
  Obtained from:	Semihalf
  Supported by:   The FreeBSD Foundation, Juniper Networks

Added:
  projects/nand/share/man/man4/nand.4
  projects/nand/share/man/man4/nandsim.4
  projects/nand/sys/dev/nand/
  projects/nand/sys/dev/nand/nand.c
  projects/nand/sys/dev/nand/nand.h
  projects/nand/sys/dev/nand/nand_bbt.c
  projects/nand/sys/dev/nand/nand_cdev.c
  projects/nand/sys/dev/nand/nand_cdev.h
  projects/nand/sys/dev/nand/nand_ecc_pos.h
  projects/nand/sys/dev/nand/nand_generic.c
  projects/nand/sys/dev/nand/nand_geom.c
  projects/nand/sys/dev/nand/nand_id.c
  projects/nand/sys/dev/nand/nand_if.m
  projects/nand/sys/dev/nand/nandbus.c
  projects/nand/sys/dev/nand/nandbus.h
  projects/nand/sys/dev/nand/nandbus_if.m
  projects/nand/sys/dev/nand/nandsim.c
  projects/nand/sys/dev/nand/nandsim.h
  projects/nand/sys/dev/nand/nandsim_chip.c
  projects/nand/sys/dev/nand/nandsim_chip.h
  projects/nand/sys/dev/nand/nandsim_ctrl.c
  projects/nand/sys/dev/nand/nandsim_log.c
  projects/nand/sys/dev/nand/nandsim_log.h
  projects/nand/sys/dev/nand/nandsim_swap.c
  projects/nand/sys/dev/nand/nandsim_swap.h
  projects/nand/sys/dev/nand/nfc_if.m
  projects/nand/sys/dev/nand/nfc_mv.c
Modified:
  projects/nand/share/man/man4/Makefile

Modified: projects/nand/share/man/man4/Makefile
==============================================================================
--- projects/nand/share/man/man4/Makefile	Sat Mar 10 02:27:04 2012	(r232757)
+++ projects/nand/share/man/man4/Makefile	Sat Mar 10 02:30:14 2012	(r232758)
@@ -250,6 +250,8 @@ MAN=	aac.4 \
 	mwlfw.4 \
 	mxge.4 \
 	my.4 \
+	nand.4 \
+	nandsim.4 \
 	natm.4 \
 	natmip.4 \
 	ncr.4 \

Added: projects/nand/share/man/man4/nand.4
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nand/share/man/man4/nand.4	Sat Mar 10 02:30:14 2012	(r232758)
@@ -0,0 +1,141 @@
+.\"
+.\" Copyright (c) 2012 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Semihalf under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 8, 2012
+.Dt NAND 4
+.Os
+.Sh NAME
+.Nm nand
+.Nd NAND Flash framework
+.Sh SYNOPSIS
+.Cd "device nand"
+.Sh DESCRIPTION
+The
+.Fx
+.Nm
+framework consists of a set of interfaces that aim to provide an extensible,
+object oriented environement for NAND controllers and NAND Flash memory chips
+from various hardware vendors, and to allow for uniform and flexible
+management of the NAND devices. It comprises of the following major
+components:
+.Bl -bullet
+.It
+NAND Flash controller (NFC) interface.
+.Pp
+Defines methods which allow to send commands as well as send/receive data
+between the controller and a NAND chip. Back-end drivers for specific NAND
+controllers plug into this interface and implement low-level routines for a
+given NAND controller.
+.Pp
+This layer implements basic functionality of a NAND Flash controller. It
+allows to send command and address to chip, drive CS (chip select line), as
+well as read/write to the selected NAND chip. This layer is independent of
+NAND chip devices actually connected to the controller.
+.It
+NAND chip interface.
+.Pp
+Provides basic operations like read page, program page, erase block. Currently
+three generic classes of drivers are available, which provide support for the
+following chips:
+.Bl -bullet
+.It
+large page
+.It
+small page
+.It
+ONFI-compliant
+.El
+.Pp
+This layer implements basic operations to be performed on a NAND chip, like
+read, program, erase, get status etc. Since these operations use specific
+commands (depending on the vendor), each chip has potentially its own
+implementation of the commands set.
+.Pp
+The framework is extensible so it is also possible to create a custom command
+set for a non standard chip support.
+.It
+NANDbus.
+.Pp
+This layer is responsible for enumerating NAND chips in the system and
+establishing the hierarchy between chips and their supervising controllers.
+.Pp
+Its main purpose is detecting type of NAND chips connected to a given chip
+select (CS line). It also allows manages locking access to the NAND
+controller. NANDbus passes requests from an active chip to the chip
+controller.
+.It
+NAND character / GEOM device.
+.Pp
+For each NAND chip found in a system a character and GEOM devices are created
+which allows to read / write directly to a device, as well as perform other
+specific operations (like via ioctl).
+.Pp
+There are two GEOM devices created for each NAND chip:
+.Bl -bullet
+.It
+raw device
+.It
+normal device
+.El
+.Pp
+Raw device allows to bypass ECC checking when reading/writing to it, while
+normal device always uses ECC algorithm to validate the read data.
+.Pp
+NAND character devices will be created for each NAND chip detected while
+probing the NAND controller.
+.El
+.Sh SEE ALSO
+.Xr libnandfs 3 ,
+.Xr gnand 4 ,
+.Xr nandsim 4 ,
+.Xr nandfs 5 ,
+.Xr cleanerd 8 ,
+.Xr makefs 8 ,
+.Xr mount_nandfs 8 ,
+.Xr nandfs 8 ,
+.Xr nandsim 8 ,
+.Xr nandtool 8 ,
+.Xr newfs_nandfs 8 ,
+.Xr umount_nandfs 8
+.Sh STANDARDS
+Open NAND Flash Interface Working Group
+.Pq Vt ONFI .
+.Sh HISTORY
+The
+.Nm
+framework support first appeared in
+.Fx 10.0 .
+.Sh AUTHOR
+The
+.Nm
+framework was designed and developed by
+.An Grzegorz Bernacki .
+This manual page was written by
+.An Rafal Jaworowski .

Added: projects/nand/share/man/man4/nandsim.4
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nand/share/man/man4/nandsim.4	Sat Mar 10 02:30:14 2012	(r232758)
@@ -0,0 +1,92 @@
+.\"
+.\" Copyright (c) 2012 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Semihalf under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 8, 2012
+.Dt NANDSIM 4
+.Os
+.Sh NAME
+.Nm nandsim
+.Nd NAND Flash simulator driver
+.Sh SYNOPSIS
+.Cd "device nand"
+.Cd "device nandsim"
+.Cd "options ALQ"
+.Sh DESCRIPTION
+The
+.Nm
+is part of the
+.Fx
+NAND framework
+.Xr nand 4
+and can be characterized with the following highlights:
+.Bl -bullet
+.It
+plugs into the
+.Xr nand 4
+framework APIs as if it were a hardware controller with real NAND chips
+connected to it
+.It
+physically part of the kernel code (either statically linked into the kernel
+image or built as a module)
+.It
+controlled with a user space program
+.Xr nandsim 8
+.El
+.Pp
+From the user perspective, the
+.Nm
+allows for imitating ONFI-compliant NAND Flash devices as if they were
+attached to the system via a virtual controller.
+.Pp
+Some
+.Nm
+features rely on the ability to log contents to a file, which is achieved
+through the
+.Xr alq 9
+facility.
+.Sh SEE ALSO
+.Xr nand 4 ,
+.Xr nandsim.conf 5 ,
+.Xr nandsim 8
+.Sh STANDARDS
+Open NAND Flash Interface Working Group
+.Pq Vt ONFI .
+.Sh HISTORY
+The
+.Nm
+support first appeared in
+.Fx 10.0 .
+.Sh AUTHOR
+The
+.Nm
+kernel driver was developed by
+.An Grzegorz Bernacki .
+This manual page was written by
+.An Rafal Jaworowski .

Added: projects/nand/sys/dev/nand/nand.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/nand/sys/dev/nand/nand.c	Sat Mar 10 02:30:14 2012	(r232758)
@@ -0,0 +1,832 @@
+/*-
+ * Copyright (C) 2009-2012 Semihalf
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/callout.h>
+#include <sys/sysctl.h>
+
+#include <dev/nand/nand.h>
+#include <dev/nand/nandbus.h>
+#include <dev/nand/nand_ecc_pos.h>
+#include "nfc_if.h"
+#include "nand_if.h"
+#include "nandbus_if.h"
+#include <machine/stdarg.h>
+
+#define NAND_RESET_DELAY	1000	/* tRST */
+#define NAND_ERASE_DELAY	3000	/* tBERS */
+#define NAND_PROG_DELAY		700	/* tPROG */
+#define NAND_READ_DELAY		50	/* tR */
+
+#define BIT0(x) ((x) & 0x1)
+#define BIT1(x) (BIT0(x >> 1))
+#define BIT2(x) (BIT0(x >> 2))
+#define BIT3(x) (BIT0(x >> 3))
+#define BIT4(x) (BIT0(x >> 4))
+#define BIT5(x) (BIT0(x >> 5))
+#define BIT6(x) (BIT0(x >> 6))
+#define BIT7(x) (BIT0(x >> 7))
+
+#define	SOFTECC_SIZE		256
+#define	SOFTECC_BYTES		3
+
+int nand_debug_flag = 0;
+SYSCTL_INT(_debug, OID_AUTO, nand_debug, CTLFLAG_RW, &nand_debug_flag, 0,
+    "NAND subsystem debug flag");
+
+static void
+nand_tunable_init(void *arg)
+{
+
+	TUNABLE_INT_FETCH("debug.nand", &nand_debug_flag);
+}
+
+SYSINIT(nand_tunables, SI_SUB_VFS, SI_ORDER_ANY, nand_tunable_init, NULL);
+
+MALLOC_DEFINE(M_NAND, "NAND", "NAND dynamic data");
+
+static void calculate_ecc(const uint8_t *, uint8_t *);
+static int correct_ecc(uint8_t *, uint8_t *, uint8_t *);
+
+void
+nand_debug(int level, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (!(nand_debug_flag & level))
+		return;
+	va_start(ap, fmt);
+	vprintf(fmt, ap);
+	va_end(ap);
+	printf("\n");
+}
+
+void
+nand_init(struct nand_softc *nand, device_t dev, int ecc_mode,
+    int ecc_bytes, int ecc_size, uint16_t *eccposition, char *cdev_name)
+{
+
+	nand->ecc.eccmode = ecc_mode;
+	nand->chip_cdev_name = cdev_name;
+
+	if (ecc_mode == NAND_ECC_SOFT) {
+		nand->ecc.eccbytes = SOFTECC_BYTES;
+		nand->ecc.eccsize = SOFTECC_SIZE;
+	} else if (ecc_mode != NAND_ECC_NONE){
+		nand->ecc.eccbytes = ecc_bytes;
+		nand->ecc.eccsize = ecc_size;
+		if (eccposition)
+			nand->ecc.eccpositions = eccposition;
+	}
+}
+
+void
+nand_onfi_set_params(struct nand_chip *chip, struct onfi_params *params)
+{
+	struct chip_geom *cg;
+
+	cg = &chip->chip_geom;
+
+	init_chip_geom(cg, params->luns, params->blocks_per_lun,
+	    params->pages_per_block, params->bytes_per_page,
+	    params->spare_bytes_per_page);
+	chip->t_bers = params->t_bers;
+	chip->t_prog = params->t_prog;
+	chip->t_r = params->t_r;
+	chip->t_ccs = params->t_ccs;
+
+	if (params->features & ONFI_FEAT_16BIT)
+		chip->flags |= NAND_16_BIT;
+}
+
+void
+nand_set_params(struct nand_chip *chip, struct nand_params *params)
+{
+	struct chip_geom *cg;
+	uint32_t blocks_per_chip;
+
+	cg = &chip->chip_geom;
+	blocks_per_chip = (params->chip_size << 20) /
+	    (params->page_size * params->pages_per_block);
+
+	init_chip_geom(cg, 1, blocks_per_chip,
+	    params->pages_per_block, params->page_size,
+	    params->oob_size);
+
+	chip->t_bers = NAND_ERASE_DELAY;
+	chip->t_prog = NAND_PROG_DELAY;
+	chip->t_r = NAND_READ_DELAY;
+	chip->t_ccs = 0;
+
+	if (params->flags & NAND_16_BIT)
+	    chip->flags |= NAND_16_BIT;
+}
+
+int
+nand_init_stat(struct nand_chip *chip)
+{
+	struct block_stat *blk_stat;
+	struct page_stat *pg_stat;
+	struct chip_geom *cg;
+	uint32_t blks, pgs;
+
+	cg = &chip->chip_geom;
+	blks = cg->blks_per_lun * cg->luns;
+	blk_stat = malloc(sizeof(struct block_stat) * blks, M_NAND,
+	    M_WAITOK | M_ZERO);
+	if (!blk_stat)
+		return (ENOMEM);
+
+	pgs = blks * cg->pgs_per_blk;
+	pg_stat = malloc(sizeof(struct page_stat) * pgs, M_NAND,
+	    M_WAITOK | M_ZERO);
+	if (!pg_stat) {
+		free(blk_stat, M_NAND);
+		return (ENOMEM);
+	}
+
+	chip->blk_stat = blk_stat;
+	chip->pg_stat = pg_stat;
+
+	return (0);
+}
+
+void
+nand_destroy_stat(struct nand_chip *chip)
+{
+
+	free(chip->pg_stat, M_NAND);
+	free(chip->blk_stat, M_NAND);
+}
+
+int
+init_chip_geom(struct chip_geom *cg, uint32_t luns, uint32_t blks_per_lun,
+    uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size)
+{
+	int shift;
+
+	if (!cg)
+		return (-1);
+
+	cg->luns = luns;
+	cg->blks_per_lun = blks_per_lun;
+	cg->blks_per_chip = blks_per_lun * luns;
+	cg->pgs_per_blk = pgs_per_blk;
+
+	cg->page_size = pg_size;
+	cg->oob_size = oob_size;
+	cg->block_size = cg->page_size * cg->pgs_per_blk;
+	cg->chip_size = cg->block_size * cg->blks_per_chip;
+
+	shift = fls(cg->pgs_per_blk - 1);
+	cg->pg_mask = (1 << shift) - 1;
+	cg->blk_shift = shift;
+
+	if (cg->blks_per_lun > 0) {
+		shift = fls(cg->blks_per_lun - 1);
+		cg->blk_mask = ((1 << shift) - 1) << cg->blk_shift;
+	} else {
+		shift = 0;
+		cg->blk_mask = 0;
+	}
+
+	cg->lun_shift = shift + cg->blk_shift;
+	shift = fls(cg->luns - 1);
+	cg->lun_mask = ((1 << shift) - 1) << cg->lun_shift;
+
+	nand_debug(NDBG_NAND, "Masks: lun 0x%x blk 0x%x page 0x%x\n"
+	    "Shifts: lun %d blk %d",
+	    cg->lun_mask, cg->blk_mask, cg->pg_mask,
+	    cg->lun_shift, cg->blk_shift);
+
+	return (0);
+}
+
+int
+nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun,
+    uint32_t *blk, uint32_t *pg)
+{
+
+	if (!cg || !lun || !blk || !pg)
+		return (-1);
+
+	if (row & ~(cg->lun_mask | cg->blk_mask | cg->pg_mask)) {
+		nand_debug(NDBG_NAND,"Address out of bounds\n");
+		return (-1);
+	}
+
+	*lun = (row & cg->lun_mask) >> cg->lun_shift;
+	*blk = (row & cg->blk_mask) >> cg->blk_shift;
+	*pg = (row & cg->pg_mask);
+
+	nand_debug(NDBG_NAND,"address %x-%x-%x\n", *lun, *blk, *pg);
+
+	return (0);
+}
+
+int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row)
+{
+	uint32_t lun, block, pg_in_blk;
+
+	if (!cg || !row)
+		return (-1);
+
+	block = page / cg->pgs_per_blk;
+	pg_in_blk = page % cg->pgs_per_blk;
+
+	lun = block / cg->blks_per_lun;
+	block = block % cg->blks_per_lun;
+
+	*row = (lun << cg->lun_shift) & cg->lun_mask;
+	*row |= ((block << cg->blk_shift) & cg->blk_mask);
+	*row |= (pg_in_blk & cg->pg_mask);
+
+	return (0);
+}
+
+int
+nand_check_page_boundary(struct nand_chip *chip, uint32_t page)
+{
+	struct chip_geom* cg;
+
+	cg = &chip->chip_geom;
+	if (page >= (cg->pgs_per_blk * cg->blks_per_lun * cg->luns)) {
+		nand_debug(NDBG_GEN,"%s: page number too big %#x\n",
+		    __func__, page);
+		return (1);
+	}
+
+	return (0);
+}
+
+void
+nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param)
+{
+	struct chip_geom *cg;
+
+	cg = &chip->chip_geom;
+	param->page_size = cg->page_size;
+	param->oob_size = cg->oob_size;
+
+	param->blocks = cg->blks_per_lun * cg->luns;
+	param->pages_per_block = cg->pgs_per_blk;
+}
+
+static uint16_t *
+default_software_ecc_positions(struct nand_chip *chip)
+{
+	struct nand_ecc_data *eccd;
+
+	eccd = &chip->nand->ecc;
+
+	if (eccd->eccpositions)
+		return (eccd->eccpositions);
+
+	switch (chip->chip_geom.oob_size) {
+	case 16:
+		return ((uint16_t *)&default_software_ecc_positions_16);
+	case 64:
+		return ((uint16_t *)&default_software_ecc_positions_64);
+	case 128:
+		return ((uint16_t *)&default_software_ecc_positions_128);
+	default:
+		return (NULL); /* No ecc bytes positions defs available */
+	}
+
+	return (NULL);
+}
+
+static void
+calculate_ecc(const uint8_t *buf, uint8_t *ecc)
+{
+	uint8_t p8, byte;
+	int i;
+
+	memset(ecc, 0, 3);
+
+	for (i = 0; i < 256; i++) {
+		byte = buf[i];
+		ecc[0] ^= (BIT0(byte) ^ BIT2(byte) ^ BIT4(byte) ^
+		    BIT6(byte)) << 2;
+		ecc[0] ^= (BIT1(byte) ^ BIT3(byte) ^ BIT5(byte) ^
+		    BIT7(byte)) << 3;
+		ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT4(byte) ^
+		    BIT5(byte)) << 4;
+		ecc[0] ^= (BIT2(byte) ^ BIT3(byte) ^ BIT6(byte) ^
+		    BIT7(byte)) << 5;
+		ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^
+		    BIT3(byte)) << 6;
+		ecc[0] ^= (BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^
+		    BIT7(byte)) << 7;
+
+		p8 = BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^
+		    BIT3(byte) ^ BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^
+		    BIT7(byte);
+
+		if (p8) {
+			ecc[2] ^= (0x1 << BIT0(i));
+			ecc[2] ^= (0x4 << BIT1(i));
+			ecc[2] ^= (0x10 << BIT2(i));
+			ecc[2] ^= (0x40 << BIT3(i));
+
+			ecc[1] ^= (0x1 << BIT4(i));
+			ecc[1] ^= (0x4 << BIT5(i));
+			ecc[1] ^= (0x10 << BIT6(i));
+			ecc[1] ^= (0x40 << BIT7(i));
+		}
+	}
+	ecc[0] = ~ecc[0];
+	ecc[1] = ~ecc[1];
+	ecc[2] = ~ecc[2];
+	ecc[0] |= 3;
+}
+
+static int
+correct_ecc(uint8_t *buf, uint8_t *calc_ecc, uint8_t *read_ecc)
+{
+	uint8_t ecc0, ecc1, ecc2, onesnum, bit, byte;
+	uint16_t addr = 0;
+
+	ecc0 = calc_ecc[0] ^ read_ecc[0];
+	ecc1 = calc_ecc[1] ^ read_ecc[1];
+	ecc2 = calc_ecc[2] ^ read_ecc[2];
+
+	if (!ecc0 && !ecc1 && !ecc2)
+		return (ECC_OK);
+
+	addr = BIT3(ecc0) | (BIT5(ecc0) << 1) | (BIT7(ecc0) << 2);
+	addr |= (BIT1(ecc2) << 3) | (BIT3(ecc2) << 4) |
+		    (BIT5(ecc2) << 5) |  (BIT7(ecc2) << 6);
+	addr |= (BIT1(ecc1) << 7) | (BIT3(ecc1) << 8) |
+		    (BIT5(ecc1) << 9) |  (BIT7(ecc1) << 10);
+
+	onesnum = 0;
+	while (ecc0 || ecc1 || ecc2) {
+		if (ecc0 & 1)
+			onesnum++;
+		if (ecc1 & 1)
+			onesnum++;
+		if (ecc2 & 1)
+			onesnum++;
+
+		ecc0 >>= 1;
+		ecc1 >>= 1;
+		ecc2 >>= 1;
+	}
+
+	if (onesnum == 11) {
+		/* Correctable error */
+		bit = addr & 7;
+		byte = addr >> 3;
+		buf[byte] ^= (1 << bit);
+		return (ECC_CORRECTABLE);
+	} else if (onesnum == 1) {
+		/* ECC error */
+		return (ECC_ERROR_ECC);
+	} else {
+		/* Uncorrectable error */
+		return (ECC_UNCORRECTABLE);
+	}
+
+	return (0);
+}
+
+int
+nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc)
+{
+	int steps = pagesize / SOFTECC_SIZE;
+	int i = 0, j = 0;
+
+	for (; i < (steps * SOFTECC_BYTES);
+	     i += SOFTECC_BYTES, j += SOFTECC_SIZE) {
+		calculate_ecc(&buf[j], &ecc[i]);
+	}
+
+	return (0);
+}
+
+int
+nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize,
+    uint8_t *readecc, uint8_t *calcecc)
+{
+	int steps = pagesize / SOFTECC_SIZE;
+	int i = 0, j = 0, ret = 0;
+
+	for (i = 0; i < (steps * SOFTECC_BYTES);
+	     i += SOFTECC_BYTES, j += SOFTECC_SIZE) {
+		ret += correct_ecc(&buf[j], &calcecc[i], &readecc[i]);
+		if (ret < 0)
+			return (ret);
+	}
+
+	return (ret);
+}
+
+static int
+offset_to_page(struct chip_geom *cg, uint32_t offset)
+{
+
+	return (offset / cg->page_size);
+}
+
+int
+nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf,
+    uint32_t len)
+{
+	struct chip_geom *cg;
+	struct nand_ecc_data *eccd;
+	struct page_stat *pg_stat;
+	device_t nandbus;
+	void *oob = NULL;
+	uint8_t *ptr;
+	uint16_t *eccpos = NULL;
+	uint32_t page, num, steps = 0;
+	int i, retval = 0, needwrite;
+
+	nand_debug(NDBG_NAND,"%p read page %x[%x]", chip, offset, len);
+	cg = &chip->chip_geom;
+	eccd = &chip->nand->ecc;
+	page = offset_to_page(cg, offset);
+	num = len / cg->page_size;
+
+	if (eccd->eccmode != NAND_ECC_NONE) {
+		steps = cg->page_size / eccd->eccsize;
+		eccpos = default_software_ecc_positions(chip);
+		oob = malloc(cg->oob_size, M_NAND, M_WAITOK);
+	}
+
+	nandbus = device_get_parent(chip->dev);
+	NANDBUS_LOCK(nandbus);
+	NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
+
+	ptr = (uint8_t *)buf;
+	while (num--) {
+		pg_stat = &(chip->pg_stat[page]);
+
+		if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) {
+			retval = ENXIO;
+			break;
+		}
+
+		if (eccd->eccmode != NAND_ECC_NONE) {
+			if (NAND_GET_ECC(chip->dev, ptr, eccd->ecccalculated,
+			    &needwrite)) {
+				retval = ENXIO;
+				break;
+			}
+			nand_debug(NDBG_ECC,"%s: ECC calculated:",
+			    __func__);
+			if (nand_debug_flag & NDBG_ECC)
+				for (i = 0; i < (eccd->eccbytes * steps); i++)
+					printf("%x ", eccd->ecccalculated[i]);
+
+			nand_debug(NDBG_ECC,"\n");
+
+			if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size,
+			    0)) {
+				retval = ENXIO;
+				break;
+			}
+			for (i = 0; i < (eccd->eccbytes * steps); i++)
+				eccd->eccread[i] = ((uint8_t *)oob)[eccpos[i]];
+
+			nand_debug(NDBG_ECC,"%s: ECC read:", __func__);
+			if (nand_debug_flag & NDBG_ECC)
+				for (i = 0; i < (eccd->eccbytes * steps); i++)
+					printf("%x ", eccd->eccread[i]);
+			nand_debug(NDBG_ECC,"\n");
+
+			retval = NAND_CORRECT_ECC(chip->dev, ptr, eccd->eccread,
+			    eccd->ecccalculated);
+
+			nand_debug(NDBG_ECC, "NAND_CORRECT_ECC() returned %d",
+			    retval);
+
+			if (retval == 0)
+				pg_stat->ecc_stat.ecc_succeded++;
+			else if (retval > 0) {
+				pg_stat->ecc_stat.ecc_corrected += retval;
+				retval = ECC_CORRECTABLE;
+			} else {
+				pg_stat->ecc_stat.ecc_failed++;
+				break;
+			}
+		}
+
+		pg_stat->page_read++;
+		page++;
+		ptr += cg->page_size;
+	}
+
+	NANDBUS_UNLOCK(nandbus);
+
+	if (oob)
+		free(oob, M_NAND);
+
+	return (retval);
+}
+
+int
+nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf,
+    uint32_t len)
+{
+	struct chip_geom *cg;
+	device_t nandbus;
+	uint8_t *ptr;
+	uint32_t page, num, end, begin = 0, begin_off;
+	int retval = 0;
+
+	cg = &chip->chip_geom;
+	page = offset_to_page(cg, offset);
+	begin_off = offset - page * cg->page_size;
+	if (begin_off) {
+		begin = cg->page_size - begin_off;
+		len -= begin;
+	}
+	num = len / cg->page_size;
+	end = len % cg->page_size;
+
+	nandbus = device_get_parent(chip->dev);
+	NANDBUS_LOCK(nandbus);
+	NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
+
+	ptr = (uint8_t *)buf;
+	if (begin_off) {
+		if (NAND_READ_PAGE(chip->dev, page, ptr, begin, begin_off)) {
+			NANDBUS_UNLOCK(nandbus);
+			return (ENXIO);
+		}
+
+		page++;
+		ptr += begin;
+	}
+
+	while (num--) {
+		if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) {
+			NANDBUS_UNLOCK(nandbus);
+			return (ENXIO);
+		}
+
+		page++;
+		ptr += cg->page_size;
+	}
+
+	if (end)
+		if (NAND_READ_PAGE(chip->dev, page, ptr, end, 0)) {
+			NANDBUS_UNLOCK(nandbus);
+			return (ENXIO);
+		}
+
+	NANDBUS_UNLOCK(nandbus);
+
+	return (retval);
+}
+
+
+int
+nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf,
+    uint32_t len)
+{
+	struct chip_geom *cg;
+	struct page_stat *pg_stat;
+	struct nand_ecc_data *eccd;
+	device_t nandbus;
+	uint32_t page, num;
+	uint8_t *oob = NULL;
+	uint16_t *eccpos = NULL;
+	int steps = 0, i, needwrite, err = 0;
+
+	nand_debug(NDBG_NAND,"%p prog page %x[%x]", chip, offset, len);
+
+	eccd = &chip->nand->ecc;
+	cg = &chip->chip_geom;
+	page = offset_to_page(cg, offset);
+	num = len / cg->page_size;
+
+	if (eccd->eccmode != NAND_ECC_NONE) {
+		steps = cg->page_size / eccd->eccsize;
+		oob = malloc(cg->oob_size, M_NAND, M_WAITOK);
+		eccpos = default_software_ecc_positions(chip);
+	}
+
+	nandbus = device_get_parent(chip->dev);
+	NANDBUS_LOCK(nandbus);
+	NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
+
+	while (num--) {
+		if (NAND_PROGRAM_PAGE(chip->dev, page, buf, cg->page_size, 0)) {
+			err = ENXIO;
+			break;
+		}
+
+		if (eccd->eccmode != NAND_ECC_NONE) {
+			if (NAND_GET_ECC(chip->dev, buf, &eccd->ecccalculated,
+			    &needwrite)) {
+				err = ENXIO;
+				break;
+			}
+			nand_debug(NDBG_ECC,"ECC calculated:");
+			if (nand_debug_flag & NDBG_ECC)
+				for (i = 0; i < (eccd->eccbytes * steps); i++)
+					printf("%x ", eccd->ecccalculated[i]);
+
+			nand_debug(NDBG_ECC,"\n");
+
+			if (needwrite) {
+				if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size,
+				    0)) {
+					err = ENXIO;
+					break;
+				}
+
+				for (i = 0; i < (eccd->eccbytes * steps); i++)
+					oob[eccpos[i]] = eccd->ecccalculated[i];
+
+				if (NAND_PROGRAM_OOB(chip->dev, page, oob,
+					    cg->oob_size, 0)) {
+					err = ENXIO;
+					break;
+				}
+			}
+		}
+
+		pg_stat = &(chip->pg_stat[page]);
+		pg_stat->page_written++;
+
+		page++;
+		buf += cg->page_size;
+	}
+
+	NANDBUS_UNLOCK(nandbus);
+
+	if (oob)
+		free(oob, M_NAND);
+
+	return (err);
+}
+
+int
+nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf,
+    uint32_t len)
+{
+	struct chip_geom *cg;
+	device_t nandbus;
+	uint8_t *ptr;
+	uint32_t page, num, end, begin = 0, begin_off;
+	int retval = 0;
+
+	cg = &chip->chip_geom;
+	page = offset_to_page(cg, offset);
+	begin_off = offset - page * cg->page_size;
+	if (begin_off) {
+		begin = cg->page_size - begin_off;
+		len -= begin;
+	}
+	num = len / cg->page_size;
+	end = len % cg->page_size;
+
+	nandbus = device_get_parent(chip->dev);
+	NANDBUS_LOCK(nandbus);
+	NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
+
+	ptr = (uint8_t *)buf;
+	if (begin_off) {
+		if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, begin, begin_off)) {
+			NANDBUS_UNLOCK(nandbus);
+			return (ENXIO);
+		}
+
+		page++;
+		ptr += begin;
+	}
+
+	while (num--) {
+		if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, cg->page_size, 0)) {
+			NANDBUS_UNLOCK(nandbus);
+			return (ENXIO);
+		}
+
+		page++;
+		ptr += cg->page_size;
+	}
+
+	if (end)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203100230.q2A2UE1a035530>