[Midnightbsd-cvs] src [10379] trunk/usr.sbin: add nand tools

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Jun 3 19:25:32 EDT 2018


Revision: 10379
          http://svnweb.midnightbsd.org/src/?rev=10379
Author:   laffer1
Date:     2018-06-03 19:25:31 -0400 (Sun, 03 Jun 2018)
Log Message:
-----------
add nand tools

Added Paths:
-----------
    trunk/usr.sbin/nandsim/
    trunk/usr.sbin/nandsim/Makefile
    trunk/usr.sbin/nandsim/nandsim.8
    trunk/usr.sbin/nandsim/nandsim.c
    trunk/usr.sbin/nandsim/nandsim_cfgparse.c
    trunk/usr.sbin/nandsim/nandsim_cfgparse.h
    trunk/usr.sbin/nandsim/nandsim_rcfile.c
    trunk/usr.sbin/nandsim/nandsim_rcfile.h
    trunk/usr.sbin/nandsim/sample.conf
    trunk/usr.sbin/nandtool/
    trunk/usr.sbin/nandtool/Makefile
    trunk/usr.sbin/nandtool/nand_erase.c
    trunk/usr.sbin/nandtool/nand_info.c
    trunk/usr.sbin/nandtool/nand_read.c
    trunk/usr.sbin/nandtool/nand_readoob.c
    trunk/usr.sbin/nandtool/nand_write.c
    trunk/usr.sbin/nandtool/nand_writeoob.c
    trunk/usr.sbin/nandtool/nandtool.8
    trunk/usr.sbin/nandtool/nandtool.c
    trunk/usr.sbin/nandtool/nandtool.h
    trunk/usr.sbin/nandtool/usage.h

Added: trunk/usr.sbin/nandsim/Makefile
===================================================================
--- trunk/usr.sbin/nandsim/Makefile	                        (rev 0)
+++ trunk/usr.sbin/nandsim/Makefile	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,9 @@
+# $MidnightBSD$
+# $FreeBSD: stable/10/usr.sbin/nandsim/Makefile 235537 2012-05-17 10:11:18Z gber $
+
+PROG=	nandsim
+SRCS=	nandsim.c nandsim_rcfile.c nandsim_cfgparse.c
+BINDIR=	/usr/sbin
+MAN=	nandsim.8
+
+.include <bsd.prog.mk>


Property changes on: trunk/usr.sbin/nandsim/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandsim/nandsim.8
===================================================================
--- trunk/usr.sbin/nandsim/nandsim.8	                        (rev 0)
+++ trunk/usr.sbin/nandsim/nandsim.8	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,230 @@
+.\" $MidnightBSD$
+.\" Copyright (c) 2010 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.
+.\"
+.\" $FreeBSD: stable/10/usr.sbin/nandsim/nandsim.8 293290 2016-01-07 00:40:51Z bdrewery $
+.\"
+.Dd August 10, 2010
+.Dt NANDSIM 8
+.Os
+.Sh NAME
+.Nm nandsim
+.Nd NAND simulator control program
+.Sh SYNOPSIS
+.Nm
+.Ic status
+.Aq ctrl_no | Fl -all  | Fl a
+.Op Fl v
+.Nm
+.Ic conf
+.Aq filename
+.Nm
+.Ic start
+.Aq ctrl_no
+.Nm
+.Ic mod
+.Aq ctrl_no:cs_no | Fl l Aq loglevel
+.Op Fl p Aq prog_time
+.Op Fl e Aq erase_time
+.Op Fl r Aq read_time
+.Op Fl E Aq error_ratio
+.Op Fl h
+.Nm
+.Ic stop
+.Aq ctrl_no
+.Nm
+.Ic error
+.Aq ctrl_no:cs_no
+.Aq page_num
+.Aq column
+.Aq length
+.Aq pattern
+.Nm
+.Ic bb
+.Aq ctrl_no:cs_no
+.Op blk_num,blk_num2,...
+.Op Fl U
+.Op Fl L
+.Nm
+.Ic freeze
+.Op ctrl_no
+.Nm
+.Ic log
+.Aq ctrl_no | Fl -all  | Fl a
+.Nm
+.Ic stats
+.Aq ctrl_no:cs_no
+.Aq page_num
+.Nm
+.Ic dump
+.Aq ctrl_no:cs_no
+.Aq filename
+.Nm
+.Ic restore
+.Aq ctrl_no:chip_no
+.Aq filename
+.Nm
+.Ic destroy
+.Aq ctrl_no[:cs_no] | Fl -all | Fl a
+.Nm
+.Ic help
+.Op Fl v
+.Sh COMMAND DESCRIPTION
+Controllers and chips are arranged into a simple hierarchy.
+There can be up to 4 controllers configured, each with 4 chip select (CS) lines.
+A given chip is connected to one of the chip selects.
+.Pp
+Controllers are specified as
+.Aq ctrl_no ;
+chip selects are specified as
+.Aq cs_no .
+.Bl -tag -width periphlist
+.It Ic status
+Gets controller(s) status. If
+.Fl a
+or
+.Fl -all
+flag is specified - command will print status of every controller
+currently available.
+Optional flag
+.Fl v
+causes printing complete information about the controller, and all
+chips attached to it.
+.It Ic conf
+Reads simulator configuration from a specified file (this includes
+the simulation "layout" i.e. controllers-chips assignments).
+Configuration changes for an already started simulation require a
+full stop-start cycle in order to take effect i.e.:
+.Bl -column
+.It nandsim stop ...
+.It nandsim destroy ...
+.Pp
+.It << edit config file >>
+.Pp
+.It nandsim conf ...
+.It nandsim start ...
+.El
+.It Ic mod
+Alters simulator parameters on-the-fly.
+If controller number and CS pair is not specified, the general
+simulator parameters (not specific to a controller or a chip) will be modified.
+Changing chip's parameters requires specifying both controller number and CS
+to which the given chip is connected.
+Parameters which can be altered:
+.Pp
+General simulator related:
+.Bl -tag -width flag
+.It Fl l Aq log_level
+change logging level to
+.Aq log_level
+.El
+.Pp
+Chip related:
+.Bl -tag -width flag
+.It Fl p Aq prog_time
+change prog time for specified chip to
+.Aq prog_time
+.It Fl e Aq erase_time
+change erase time for specified chip to
+.Aq erase_time
+.It Fl r Aq read_time
+change read time for specified chip to
+.Aq read_time
+.It Fl E Aq error_ratio
+change error ratio for specified chip to
+.Aq error_ratio .
+Error ratio is a number of errors per million read/write bytes.
+.El
+.Pp
+Additionally, flag
+.Fl h
+will list parameters which can be altered.
+.El
+.Bl -tag -width periphlist
+.It Ic bb
+Marks/unmarks a specified block as bad.
+To mark/unmark the bad condition an a block, the following parameters
+have to be supplied: controller number, CS number, and at least one
+block number.
+It is possible to specify multiple blocks, by separating blocks numbers
+with a comma.
+The following options can be used for the 'bb' command:
+.Bl -tag -width flag
+.It Fl U
+unmark the bad previously marked block as bad.
+.It Fl L
+list all blocks marked as bad on a given chip.
+.El
+.It Ic log
+Prints activity log of the specified controller to stdout; if
+controller number is not specified, logs for all available
+controllers are printed.
+.It Ic stats
+Print statistics of the selected controller, chip and page.
+Statistics includes read count, write count, raw read count, raw
+write count, ECC stats (succeeded corrections, failed correction).
+.It Ic dump
+Dumps a snaphot of a single chip (including data and bad blocks
+information, wearout level) into the file.
+.It Ic restore
+Restores chip state from a dump-file snapshot (produced previously
+with the 'dump' command).
+.It Ic start
+Starts a controller i.e. the simulation.
+.It Ic stop
+Stops an already started controller; if the controller number is not
+supplied, attempts to stop all currently working controllers.
+.It Ic destroy
+Removes existing active chip/controller and its configuration from
+memory and releases the resources.
+Specifying flag
+.Fl a
+or
+.Fl -all
+causes removal of every chip and controller.
+Controller must be stopped in order to be destroyed.
+.It Ic error
+Directly overwrites a certain number of bytes in the specified page
+at a given offset with a supplied pattern (which mimics the
+corruption of flash contents).
+.It Ic help
+Prints synopsis,
+.Fl v
+gives more verbose output.
+.It Ic freeze
+Stops simulation of given controller (simulates power-loss).
+All commands issues to any chip on this controller are ignored.
+.El
+.Sh SEE ALSO
+.Xr nand 4 ,
+.Xr nandsim 4
+.Xr nandsim.conf 5
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 10.0 .
+.Sh AUTHOR
+This utility was written by
+.An Lukasz Wojcik .


Property changes on: trunk/usr.sbin/nandsim/nandsim.8
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandsim/nandsim.c
===================================================================
--- trunk/usr.sbin/nandsim/nandsim.c	                        (rev 0)
+++ trunk/usr.sbin/nandsim/nandsim.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,1398 @@
+/* $MidnightBSD$ */
+/*-
+ * 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 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.
+ */
+
+/*
+ * Control application for the NAND simulator.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/nandsim/nandsim.c 293290 2016-01-07 00:40:51Z bdrewery $");
+
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <dev/nand/nandsim.h>
+#include <dev/nand/nand_dev.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sysexits.h>
+
+#include "nandsim_cfgparse.h"
+
+#define SIMDEVICE	"/dev/nandsim.ioctl"
+
+#define error(fmt, args...) do { \
+    printf("ERROR: " fmt "\n", ##args); } while (0)
+
+#define warn(fmt, args...) do { \
+    printf("WARNING: " fmt "\n", ##args); } while (0)
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define debug(fmt, args...) do { \
+    printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0)
+#else
+#define debug(fmt, args...) do {} while(0)
+#endif
+
+#define NANDSIM_RAM_LOG_SIZE 16384
+
+#define MSG_NOTRUNNING		"Controller#%d is not running.Please start" \
+    " it first."
+#define MSG_RUNNING		"Controller#%d is already running!"
+#define MSG_CTRLCHIPNEEDED	"You have to specify ctrl_no:cs_no pair!"
+#define MSG_STATUSACQCTRLCHIP	"Could not acquire status for ctrl#%d chip#%d"
+#define MSG_STATUSACQCTRL	"Could not acquire status for ctrl#%d"
+#define MSG_NOCHIP		"There is no such chip configured (chip#%d "\
+    "at ctrl#%d)!"
+
+#define MSG_NOCTRL		"Controller#%d is not configured!"
+#define MSG_NOTCONFIGDCTRLCHIP	"Chip connected to ctrl#%d at cs#%d " \
+    "is not configured."
+
+typedef int (commandfunc_t)(int , char **);
+
+static struct nandsim_command *getcommand(char *);
+static int parse_devstring(char *, int *, int *);
+static void printchip(struct sim_chip *, uint8_t);
+static void printctrl(struct sim_ctrl *);
+static int opendev(int *);
+static commandfunc_t cmdstatus;
+static commandfunc_t cmdconf;
+static commandfunc_t cmdstart;
+static commandfunc_t cmdstop;
+static commandfunc_t cmdmod;
+static commandfunc_t cmderror;
+static commandfunc_t cmdbb;
+static commandfunc_t cmdfreeze;
+static commandfunc_t cmdlog;
+static commandfunc_t cmdstats;
+static commandfunc_t cmddump;
+static commandfunc_t cmdrestore;
+static commandfunc_t cmddestroy;
+static commandfunc_t cmdhelp;
+static int checkusage(int, int, char **);
+static int is_chip_created(int, int, int *);
+static int is_ctrl_created(int, int *);
+static int is_ctrl_running(int, int *);
+static int assert_chip_connected(int , int);
+static int printstats(int, int, uint32_t, int);
+
+struct nandsim_command {
+	const char	*cmd_name;	/* Command name */
+	commandfunc_t	*commandfunc;	/* Ptr to command function */
+	uint8_t		req_argc;	/* Mandatory arguments count */
+	const char	*usagestring;	/* Usage string */
+};
+
+static struct nandsim_command commands[] = {
+	{"status", cmdstatus, 1,
+	    "status <ctl_no|--all|-a> [-v]\n" },
+	{"conf", cmdconf, 1,
+	    "conf <filename>\n" },
+	{"start", cmdstart, 1,
+	    "start <ctrl_no>\n" },
+	{"mod", cmdmod, 2,
+	    "mod [-l <loglevel>] | <ctl_no:cs_no> [-p <prog_time>]\n"
+	    "\t[-e <erase_time>] [-r <read_time>]\n"
+	    "\t[-E <error_ratio>] | [-h]\n" },
+	{"stop", cmdstop, 1,
+	    "stop <ctrl_no>\n" },
+	{"error", cmderror, 5,
+	    "error <ctrl_no:cs_no> <page_num> <column> <length> <pattern>\n" },
+	{"bb", cmdbb, 2,
+	    "bb <ctl_no:cs_no>  [blk_num1,blk_num2,..] [-U] [-L]\n" },
+	{"freeze", cmdfreeze, 1,
+	    "freeze [ctrl_no]\n" },
+	{"log", cmdlog, 1,
+	    "log <ctrl_no|--all|-a>\n" },
+	{"stats", cmdstats, 2,
+	    "stats <ctrl_no:cs_no> <pagenumber>\n" },
+	{"dump", cmddump, 2,
+	    "dump <ctrl_no:cs_no> <filename>\n" },
+	{"restore", cmdrestore, 2,
+	    "restore <ctrl_no:chip_no> <filename>\n" },
+	{"destroy", cmddestroy, 1,
+	    "destroy <ctrl_no[:cs_no]|--all|-a>\n" },
+	{"help", cmdhelp, 0,
+	    "help [-v]" },
+	{NULL, NULL, 0, NULL},
+};
+
+
+/* Parse command name, and start appropriate function */
+static struct nandsim_command*
+getcommand(char *arg)
+{
+	struct nandsim_command *opts;
+
+	for (opts = commands; (opts != NULL) &&
+	    (opts->cmd_name != NULL); opts++) {
+		if (strcmp(opts->cmd_name, arg) == 0)
+			return (opts);
+	}
+	return (NULL);
+}
+
+/*
+ * Parse given string in format <ctrl_no>:<cs_no>, if possible -- set
+ * ctrl and/or cs, and return 0 (success) or 1 (in case of error).
+ *
+ * ctrl == 0xff && chip == 0xff  : '--all' flag specified
+ * ctrl != 0xff && chip != 0xff  : both ctrl & chip were specified
+ * ctrl != 0xff && chip == 0xff  : only ctrl was specified
+ */
+static int
+parse_devstring(char *str, int *ctrl, int *cs)
+{
+	char *tmpstr;
+	unsigned int num = 0;
+
+	/* Ignore white spaces at the beginning */
+	while (isspace(*str) && (*str != '\0'))
+		str++;
+
+	*ctrl = 0xff;
+	*cs = 0xff;
+	if (strcmp(str, "--all") == 0 ||
+	    strcmp(str, "-a") == 0) {
+		/* If --all or -a is specified, ctl==chip==0xff */
+		debug("CTRL=%d CHIP=%d\n", *ctrl, *cs);
+		return (0);
+	}
+	/* Separate token and try to convert it to int */
+	tmpstr = (char *)strtok(str, ":");
+	if ((tmpstr != NULL) && (*tmpstr != '\0')) {
+		if (convert_arguint(tmpstr, &num) != 0)
+			return (1);
+
+		if (num > MAX_SIM_DEV - 1) {
+			error("Invalid ctrl_no supplied: %s. Valid ctrl_no "
+			    "value must lie between 0 and 3!", tmpstr);
+			return (1);
+		}
+
+		*ctrl = num;
+		tmpstr = (char *)strtok(NULL, ":");
+
+		if ((tmpstr != NULL) && (*tmpstr != '\0')) {
+			if (convert_arguint(tmpstr, &num) != 0)
+				return (1);
+
+			/* Check if chip_no is valid */
+			if (num > MAX_CTRL_CS - 1) {
+				error("Invalid chip_no supplied: %s. Valid "
+				    "chip_no value must lie between 0 and 3!",
+				    tmpstr);
+				return (1);
+			}
+			*cs = num;
+		}
+	} else
+		/* Empty devstring supplied */
+		return (1);
+
+	debug("CTRL=%d CHIP=%d\n", *ctrl, *cs);
+	return (0);
+}
+
+static int
+opendev(int *fd)
+{
+
+	*fd = open(SIMDEVICE, O_RDWR);
+	if (*fd == -1) {
+		error("Could not open simulator device file (%s)!",
+		    SIMDEVICE);
+		return (EX_OSFILE);
+	}
+	return (EX_OK);
+}
+
+static int
+opencdev(int *cdevd, int ctrl, int chip)
+{
+	char fname[255];
+
+	sprintf(fname, "/dev/nandsim%d.%d", ctrl, chip);
+	*cdevd = open(fname, O_RDWR);
+	if (*cdevd == -1)
+		return (EX_NOINPUT);
+
+	return (EX_OK);
+}
+
+/*
+ * Check if given arguments count match requirements. If no, or
+ * --help (-h) flag is specified -- return 1 (print usage)
+ */
+static int
+checkusage(int gargc, int argsreqd, char **gargv)
+{
+
+	if (gargc < argsreqd + 2 || (gargc >= (argsreqd + 2) &&
+	    (strcmp(gargv[1], "--help") == 0 ||
+	    strcmp(gargv[1], "-h") == 0)))
+		return (1);
+
+	return (0);
+}
+
+static int
+cmdstatus(int gargc, char **gargv)
+{
+	int chip = 0, ctl = 0, err = 0, fd, idx, idx2, start, stop;
+	uint8_t verbose = 0;
+	struct sim_ctrl ctrlconf;
+	struct sim_chip chipconf;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err) {
+		return (EX_USAGE);
+	} else if (ctl == 0xff) {
+		/* Every controller */
+		start = 0;
+		stop = MAX_SIM_DEV-1;
+	} else {
+		/* Specified controller only */
+		start = ctl;
+		stop = ctl;
+	}
+
+	if (opendev(&fd) != EX_OK)
+		return (EX_OSFILE);
+
+	for (idx = 0; idx < gargc; idx ++)
+		if (strcmp(gargv[idx], "-v") == 0 ||
+		    strcmp(gargv[idx], "--verbose") == 0)
+			verbose = 1;
+
+	for (idx = start; idx <= stop; idx++) {
+		ctrlconf.num = idx;
+		err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrlconf);
+		if (err) {
+			err = EX_SOFTWARE;
+			error(MSG_STATUSACQCTRL, idx);
+			continue;
+		}
+
+		printctrl(&ctrlconf);
+
+		for (idx2 = 0; idx2 < MAX_CTRL_CS; idx2++) {
+			chipconf.num = idx2;
+			chipconf.ctrl_num = idx;
+
+			err = ioctl(fd, NANDSIM_STATUS_CHIP, &chipconf);
+			if (err) {
+				err = EX_SOFTWARE;
+				error(MSG_STATUSACQCTRL, idx);
+				continue;
+			}
+
+			printchip(&chipconf, verbose);
+		}
+	}
+	close(fd);
+	return (err);
+}
+
+static int
+cmdconf(int gargc __unused, char **gargv)
+{
+	int err;
+
+	err = parse_config(gargv[2], SIMDEVICE);
+	if (err)
+		return (EX_DATAERR);
+
+	return (EX_OK);
+}
+
+static int
+cmdstart(int gargc __unused, char **gargv)
+{
+	int chip = 0, ctl = 0, err = 0, fd, running, state;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err)
+		return (EX_USAGE);
+
+	err = is_ctrl_created(ctl, &state);
+	if (err) {
+		return (EX_SOFTWARE);
+	} else if (state == 0) {
+		error(MSG_NOCTRL, ctl);
+		return (EX_SOFTWARE);
+	}
+
+	err = is_ctrl_running(ctl, &running);
+	if (err)
+		return (EX_SOFTWARE);
+
+	if (running) {
+		warn(MSG_RUNNING, ctl);
+	} else {
+		if (opendev(&fd) != EX_OK)
+			return (EX_OSFILE);
+
+		err = ioctl(fd, NANDSIM_START_CTRL, &ctl);
+		close(fd);
+		if (err) {
+			error("Cannot start controller#%d", ctl);
+			err = EX_SOFTWARE;
+		}
+	}
+	return (err);
+}
+
+static int
+cmdstop(int gargc __unused, char **gargv)
+{
+	int chip = 0, ctl = 0, err = 0, fd, running;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err)
+		return (EX_USAGE);
+
+	err = is_ctrl_running(ctl, &running);
+	if (err)
+		return (EX_SOFTWARE);
+
+	if (!running) {
+		error(MSG_NOTRUNNING, ctl);
+	} else {
+		if (opendev(&fd) != EX_OK)
+			return (EX_OSFILE);
+
+		err = ioctl(fd, NANDSIM_STOP_CTRL, &ctl);
+		close(fd);
+		if (err) {
+			error("Cannot stop controller#%d", ctl);
+			err = EX_SOFTWARE;
+		}
+	}
+
+	return (err);
+}
+
+static int
+cmdmod(int gargc __unused, char **gargv)
+{
+	int chip, ctl, err = 0, fd = -1, i;
+	struct sim_mod mods;
+
+	if (gargc >= 4) {
+		if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2],
+		    "-l") == 0) {
+			/* Set loglevel (ctrl:chip pair independent) */
+			mods.field = SIM_MOD_LOG_LEVEL;
+
+			if (convert_arguint(gargv[3], &mods.new_value) != 0)
+				return (EX_SOFTWARE);
+
+			if (opendev(&fd) != EX_OK)
+				return (EX_OSFILE);
+
+			err = ioctl(fd, NANDSIM_MODIFY, &mods);
+			if (err) {
+				error("simulator parameter %s could not be "
+				    "modified !", gargv[3]);
+				close(fd);
+				return (EX_SOFTWARE);
+			}
+
+			debug("request : loglevel = %d\n", mods.new_value);
+			close(fd);
+			return (EX_OK);
+		}
+	}
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err)
+		return (EX_USAGE);
+
+	else if (chip == 0xff) {
+		error(MSG_CTRLCHIPNEEDED);
+		return (EX_USAGE);
+	}
+
+	if (!assert_chip_connected(ctl, chip))
+		return (EX_SOFTWARE);
+
+	if (opendev(&fd) != EX_OK)
+		return (EX_OSFILE);
+
+	/* Find out which flags were passed */
+	for (i = 3; i < gargc; i++) {
+
+		if (convert_arguint(gargv[i + 1], &mods.new_value) != 0)
+			continue;
+
+		if (strcmp(gargv[i], "--prog-time") == 0 ||
+		    strcmp(gargv[i], "-p") == 0) {
+
+			mods.field = SIM_MOD_PROG_TIME;
+			debug("request : progtime = %d\n", mods.new_value);
+
+		} else if (strcmp(gargv[i], "--erase-time") == 0 ||
+		    strcmp(gargv[i], "-e") == 0) {
+
+			mods.field = SIM_MOD_ERASE_TIME;
+			debug("request : eraseime = %d\n", mods.new_value);
+
+		} else if (strcmp(gargv[i], "--read-time") == 0 ||
+		    strcmp(gargv[i], "-r") == 0) {
+
+			mods.field = SIM_MOD_READ_TIME;
+			debug("request : read_time = %d\n", mods.new_value);
+
+		} else if (strcmp(gargv[i], "--error-ratio") == 0 ||
+		    strcmp(gargv[i], "-E") == 0) {
+
+			mods.field = SIM_MOD_ERROR_RATIO;
+			debug("request : error_ratio = %d\n", mods.new_value);
+
+		} else {
+			/* Flag not recognized, or nothing specified. */
+			error("Unrecognized flag:%s\n", gargv[i]);
+			if (fd >= 0)
+				close(fd);
+			return (EX_USAGE);
+		}
+
+		mods.chip_num = chip;
+		mods.ctrl_num = ctl;
+
+		/* Call appropriate ioctl */
+		err = ioctl(fd, NANDSIM_MODIFY, &mods);
+		if (err) {
+			error("simulator parameter %s could not be modified! ",
+			    gargv[i]);
+			continue;
+		}
+		i++;
+	}
+	close(fd);
+	return (EX_OK);
+}
+
+static int
+cmderror(int gargc __unused, char **gargv)
+{
+	uint32_t page, column, len, pattern;
+	int chip = 0, ctl = 0, err = 0, fd;
+	struct sim_error sim_err;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err)
+		return (EX_USAGE);
+
+	if (chip == 0xff) {
+		error(MSG_CTRLCHIPNEEDED);
+		return (EX_USAGE);
+	}
+
+	if (convert_arguint(gargv[3], &page) ||
+	    convert_arguint(gargv[4], &column) ||
+	    convert_arguint(gargv[5], &len) ||
+	    convert_arguint(gargv[6], &pattern))
+		return (EX_SOFTWARE);
+
+	if (!assert_chip_connected(ctl, chip))
+		return (EX_SOFTWARE);
+
+	sim_err.page_num = page;
+	sim_err.column = column;
+	sim_err.len = len;
+	sim_err.pattern = pattern;
+	sim_err.ctrl_num = ctl;
+	sim_err.chip_num = chip;
+
+	if (opendev(&fd) != EX_OK)
+		return (EX_OSFILE);
+
+	err = ioctl(fd, NANDSIM_INJECT_ERROR, &sim_err);
+
+	close(fd);
+	if (err) {
+		error("Could not inject error !");
+		return (EX_SOFTWARE);
+	}
+	return (EX_OK);
+}
+
+static int
+cmdbb(int gargc, char **gargv)
+{
+	struct sim_block_state bs;
+	struct chip_param_io cparams;
+	uint32_t blkidx;
+	int c, cdevd, chip = 0, ctl = 0, err = 0, fd, idx;
+	uint8_t flagL = 0, flagU = 0;
+	int *badblocks = NULL;
+
+	/* Check for --list/-L or --unmark/-U flags */
+	for (idx = 3; idx < gargc; idx++) {
+		if (strcmp(gargv[idx], "--list") == 0 ||
+		    strcmp(gargv[idx], "-L") == 0)
+			flagL = idx;
+		if (strcmp(gargv[idx], "--unmark") == 0 ||
+		    strcmp(gargv[idx], "-U") == 0)
+			flagU = idx;
+	}
+
+	if (flagL == 2 || flagU == 2 || flagU == 3)
+		return (EX_USAGE);
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err) {
+		return (EX_USAGE);
+	}
+	if (chip == 0xff || ctl == 0xff) {
+		error(MSG_CTRLCHIPNEEDED);
+		return (EX_USAGE);
+	}
+
+	bs.ctrl_num = ctl;
+	bs.chip_num = chip;
+
+	if (!assert_chip_connected(ctl, chip))
+		return (EX_SOFTWARE);
+
+	if (opencdev(&cdevd, ctl, chip) != EX_OK)
+		return (EX_OSFILE);
+
+	err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams);
+	if (err)
+		return (EX_SOFTWARE);
+
+	close(cdevd);
+
+	bs.ctrl_num = ctl;
+	bs.chip_num = chip;
+
+	if (opendev(&fd) != EX_OK)
+		return (EX_OSFILE);
+
+	if (flagL != 3) {
+		/*
+		 * Flag -L was specified either after blocklist or was not
+		 * specified at all.
+		 */
+		c = parse_intarray(gargv[3], &badblocks);
+
+		for (idx = 0; idx < c; idx++) {
+			bs.block_num = badblocks[idx];
+			/* Do not change wearout */
+			bs.wearout = -1;
+			bs.state = (flagU == 0) ? NANDSIM_BAD_BLOCK :
+			    NANDSIM_GOOD_BLOCK;
+
+			err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs);
+			if (err) {
+				error("Could not set bad block(%d) for "
+				    "controller (%d)!",
+				    badblocks[idx], ctl);
+				err = EX_SOFTWARE;
+				break;
+			}
+		}
+	}
+	if (flagL != 0) {
+		/* If flag -L was specified (anywhere) */
+		for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
+			bs.block_num = blkidx;
+			/* Do not change the wearout */
+			bs.wearout = -1;
+			err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs);
+			if (err) {
+				error("Could not acquire block state");
+				err = EX_SOFTWARE;
+				continue;
+			}
+			printf("Block#%d: wear count: %d %s\n", blkidx,
+			    bs.wearout,
+			    (bs.state == NANDSIM_BAD_BLOCK) ? "BAD":"GOOD");
+		}
+	}
+	close(fd);
+	return (err);
+}
+
+static int
+cmdfreeze(int gargc __unused, char **gargv)
+{
+	int chip = 0, ctl = 0, err = 0, fd, i, start = 0, state, stop = 0;
+	struct sim_ctrl_chip ctrlchip;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err)
+		return (EX_USAGE);
+
+	if (ctl == 0xff) {
+		error("You have to specify at least controller number");
+		return (EX_USAGE);
+	}
+
+	if (ctl != 0xff && chip == 0xff) {
+		start = 0;
+		stop = MAX_CTRL_CS - 1;
+	} else {
+		start = chip;
+		stop = chip;
+	}
+
+	ctrlchip.ctrl_num = ctl;
+
+	err = is_ctrl_running(ctl, &state);
+	if (err)
+		return (EX_SOFTWARE);
+	if (state == 0) {
+		error(MSG_NOTRUNNING, ctl);
+		return (EX_SOFTWARE);
+	}
+
+	if (opendev(&fd) != EX_OK)
+		return (EX_OSFILE);
+
+	for (i = start; i <= stop; i++) {
+		err = is_chip_created(ctl, i, &state);
+		if (err)
+			return (EX_SOFTWARE);
+		else if (state == 0) {
+			continue;
+		}
+
+		ctrlchip.chip_num = i;
+		err = ioctl(fd, NANDSIM_FREEZE, &ctrlchip);
+		if (err) {
+			error("Could not freeze ctrl#%d chip#%d", ctl, i);
+			close(fd);
+			return (EX_SOFTWARE);
+		}
+	}
+	close(fd);
+	return (EX_OK);
+}
+
+static int
+cmdlog(int gargc __unused, char **gargv)
+{
+	struct sim_log log;
+	int chip = 0, ctl = 0, err = 0, fd, idx, start = 0, stop = 0;
+	char *logbuf;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err)
+		return (EX_USAGE);
+
+	logbuf = (char *)malloc(sizeof(char) * NANDSIM_RAM_LOG_SIZE);
+	if (logbuf == NULL) {
+		error("Not enough memory to create log buffer");
+		return (EX_SOFTWARE);
+	}
+
+	memset(logbuf, 0, NANDSIM_RAM_LOG_SIZE);
+	log.log = logbuf;
+	log.len = NANDSIM_RAM_LOG_SIZE;
+
+	if (ctl == 0xff) {
+		start = 0;
+		stop = MAX_SIM_DEV-1;
+	} else {
+		start = ctl;
+		stop = ctl;
+	}
+
+	if (opendev(&fd) != EX_OK) {
+		free(logbuf);
+		return (EX_OSFILE);
+	}
+
+	/* Print logs for selected controller(s) */
+	for (idx = start; idx <= stop; idx++) {
+		log.ctrl_num = idx;
+
+		err = ioctl(fd, NANDSIM_PRINT_LOG, &log);
+		if (err) {
+			error("Could not get log for controller %d!", idx);
+			continue;
+		}
+
+		printf("Logs for controller#%d:\n%s\n", idx, logbuf);
+	}
+
+	free(logbuf);
+	close(fd);
+	return (EX_OK);
+}
+
+static int
+cmdstats(int gargc __unused, char **gargv)
+{
+	int cdevd, chip = 0, ctl = 0, err = 0;
+	uint32_t pageno = 0;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+
+	if (err)
+		return (EX_USAGE);
+
+	if (chip == 0xff) {
+		error(MSG_CTRLCHIPNEEDED);
+		return (EX_USAGE);
+	}
+
+	if (convert_arguint(gargv[3], &pageno) != 0)
+		return (EX_USAGE);
+
+	if (!assert_chip_connected(ctl, chip))
+		return (EX_SOFTWARE);
+
+	if (opencdev(&cdevd, ctl, chip) != EX_OK)
+		return (EX_OSFILE);
+
+	err = printstats(ctl, chip, pageno, cdevd);
+	if (err) {
+		close(cdevd);
+		return (EX_SOFTWARE);
+	}
+	close(cdevd);
+	return (EX_OK);
+}
+
+static int
+cmddump(int gargc __unused, char **gargv)
+{
+	struct sim_dump dump;
+	struct sim_block_state bs;
+	struct chip_param_io cparams;
+	int chip = 0, ctl = 0, err = EX_OK, fd, dumpfd;
+	uint32_t blkidx, bwritten = 0, totalwritten = 0;
+	void *buf;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err)
+		return (EX_USAGE);
+
+	if (chip == 0xff || ctl == 0xff) {
+		error(MSG_CTRLCHIPNEEDED);
+		return (EX_USAGE);
+	}
+
+	if (!assert_chip_connected(ctl, chip))
+		return (EX_SOFTWARE);
+
+	if (opencdev(&fd, ctl, chip) != EX_OK)
+		return (EX_OSFILE);
+
+	err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams);
+	if (err) {
+		error("Cannot get parameters for chip %d:%d", ctl, chip);
+		close(fd);
+		return (EX_SOFTWARE);
+	}
+	close(fd);
+
+	dump.ctrl_num = ctl;
+	dump.chip_num = chip;
+
+	dump.len = cparams.pages_per_block * (cparams.page_size +
+	    cparams.oob_size);
+
+	buf = malloc(dump.len);
+	if (buf == NULL) {
+		error("Could not allocate memory!");
+		return (EX_SOFTWARE);
+	}
+	dump.data = buf;
+
+	errno = 0;
+	dumpfd = open(gargv[3], O_WRONLY | O_CREAT, 0666);
+	if (dumpfd == -1) {
+		error("Cannot create dump file.");
+		free(buf);
+		return (EX_SOFTWARE);
+	}
+
+	if (opendev(&fd)) {
+		close(dumpfd);
+		free(buf);
+		return (EX_SOFTWARE);
+	}
+
+	bs.ctrl_num = ctl;
+	bs.chip_num = chip;
+
+	/* First uint32_t in file shall contain block count */
+	if (write(dumpfd, &cparams, sizeof(cparams)) < (int)sizeof(cparams)) {
+		error("Error writing to dumpfile!");
+		close(fd);
+		close(dumpfd);
+		free(buf);
+		return (EX_SOFTWARE);
+	}
+
+	/*
+	 * First loop acquires blocks states and writes them to
+	 * the dump file.
+	 */
+	for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
+		bs.block_num = blkidx;
+		err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs);
+		if (err) {
+			error("Could not get bad block(%d) for "
+			    "controller (%d)!", blkidx, ctl);
+			close(fd);
+			close(dumpfd);
+			free(buf);
+			return (EX_SOFTWARE);
+		}
+
+		bwritten = write(dumpfd, &bs, sizeof(bs));
+		if (bwritten != sizeof(bs)) {
+			error("Error writing to dumpfile");
+			close(fd);
+			close(dumpfd);
+			free(buf);
+			return (EX_SOFTWARE);
+		}
+	}
+
+	/* Second loop dumps the data */
+	for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
+		debug("Block#%d...", blkidx);
+		dump.block_num = blkidx;
+
+		err = ioctl(fd, NANDSIM_DUMP, &dump);
+		if (err) {
+			error("Could not dump ctrl#%d chip#%d "
+			    "block#%d", ctl, chip, blkidx);
+			err = EX_SOFTWARE;
+			break;
+		}
+
+		bwritten = write(dumpfd, dump.data, dump.len);
+		if (bwritten != dump.len) {
+			error("Error writing to dumpfile");
+			err = EX_SOFTWARE;
+			break;
+		}
+		debug("OK!\n");
+		totalwritten += bwritten;
+	}
+	printf("%d out of %d B written.\n", totalwritten, dump.len * blkidx);
+
+	close(fd);
+	close(dumpfd);
+	free(buf);
+	return (err);
+}
+
+static int
+cmdrestore(int gargc __unused, char **gargv)
+{
+	struct sim_dump dump;
+	struct sim_block_state bs;
+	struct stat filestat;
+	int chip = 0, ctl = 0, err = 0, fd, dumpfd = -1;
+	uint32_t blkidx, blksz, fsize = 0, expfilesz;
+	void *buf;
+	struct chip_param_io cparams, dumpcparams;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+	if (err)
+		return (EX_USAGE);
+	else if (ctl == 0xff) {
+		error(MSG_CTRLCHIPNEEDED);
+		return (EX_USAGE);
+	}
+
+	if (!assert_chip_connected(ctl, chip))
+		return (EX_SOFTWARE);
+
+	/* Get chip geometry */
+	if (opencdev(&fd, ctl, chip) != EX_OK)
+		return (EX_OSFILE);
+
+	err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams);
+	if (err) {
+		error("Cannot get parameters for chip %d:%d", ctl, chip);
+		close(fd);
+		return (err);
+	}
+	close(fd);
+
+	/* Obtain dump file size */
+	errno = 0;
+	if (stat(gargv[3], &filestat) != 0) {
+		error("Could not acquire file size! : %s",
+		    strerror(errno));
+		return (EX_IOERR);
+	}
+
+	fsize = filestat.st_size;
+	blksz = cparams.pages_per_block * (cparams.page_size +
+	    cparams.oob_size);
+
+	/* Expected dump file size for chip */
+	expfilesz = cparams.blocks * (blksz + sizeof(bs)) + sizeof(cparams);
+
+	if (fsize != expfilesz) {
+		error("File size does not match chip geometry (file size: %d"
+		    ", dump size: %d)", fsize, expfilesz);
+		return (EX_SOFTWARE);
+	}
+
+	dumpfd = open(gargv[3], O_RDONLY);
+	if (dumpfd == -1) {
+		error("Could not open dump file!");
+		return (EX_IOERR);
+	}
+
+	/* Read chip params saved in dumpfile */
+	read(dumpfd, &dumpcparams, sizeof(dumpcparams));
+
+	/* XXX */
+	if (bcmp(&dumpcparams, &cparams, sizeof(cparams)) != 0) {
+		error("Supplied dump is created for a chip with different "
+		    "chip configuration!");
+		close(dumpfd);
+		return (EX_SOFTWARE);
+	}
+
+	if (opendev(&fd) != EX_OK) {
+		close(dumpfd);
+		return (EX_OSFILE);
+	}
+
+	buf = malloc(blksz);
+	if (buf == NULL) {
+		error("Could not allocate memory for block buffer");
+		close(dumpfd);
+		close(fd);
+		return (EX_SOFTWARE);
+	}
+
+	dump.ctrl_num = ctl;
+	dump.chip_num = chip;
+	dump.data = buf;
+	/* Restore block states and wearouts */
+	for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
+		dump.block_num = blkidx;
+		if (read(dumpfd, &bs, sizeof(bs)) != sizeof(bs)) {
+			error("Error reading dumpfile");
+			close(dumpfd);
+			close(fd);
+			free(buf);
+			return (EX_SOFTWARE);
+		}
+		bs.ctrl_num = ctl;
+		bs.chip_num = chip;
+		debug("BLKIDX=%d BLOCKS=%d CTRL=%d CHIP=%d STATE=%d\n"
+		    "WEAROUT=%d BS.CTRL_NUM=%d BS.CHIP_NUM=%d\n",
+		    blkidx, cparams.blocks, dump.ctrl_num, dump.chip_num,
+		    bs.state, bs.wearout, bs.ctrl_num, bs.chip_num);
+
+		err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs);
+		if (err) {
+			error("Could not set bad block(%d) for "
+			    "controller: %d, chip: %d!", blkidx, ctl, chip);
+			close(dumpfd);
+			close(fd);
+			free(buf);
+			return (EX_SOFTWARE);
+		}
+	}
+	/* Restore data */
+	for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
+		errno = 0;
+		dump.len = read(dumpfd, buf, blksz);
+		if (errno) {
+			error("Failed to read block#%d from dumpfile.", blkidx);
+			err = EX_SOFTWARE;
+			break;
+		}
+		dump.block_num = blkidx;
+		err = ioctl(fd, NANDSIM_RESTORE, &dump);
+		if (err) {
+			error("Could not restore block#%d of ctrl#%d chip#%d"
+			    ": %s", blkidx, ctl, chip, strerror(errno));
+			err = EX_SOFTWARE;
+			break;
+		}
+	}
+
+	free(buf);
+	close(dumpfd);
+	close(fd);
+	return (err);
+
+}
+
+static int
+cmddestroy(int gargc __unused, char **gargv)
+{
+	int chip = 0, ctl = 0, err = 0, fd, idx, idx2, state;
+	int chipstart, chipstop, ctrlstart, ctrlstop;
+	struct sim_chip_destroy chip_destroy;
+
+	err = parse_devstring(gargv[2], &ctl, &chip);
+
+	if (err)
+		return (EX_USAGE);
+
+	if (ctl == 0xff) {
+		/* Every chip at every controller */
+		ctrlstart = chipstart = 0;
+		ctrlstop = MAX_SIM_DEV - 1;
+		chipstop = MAX_CTRL_CS - 1;
+	} else {
+		ctrlstart = ctrlstop = ctl;
+		if (chip == 0xff) {
+			/* Every chip at selected controller */
+			chipstart = 0;
+			chipstop = MAX_CTRL_CS - 1;
+		} else
+			/* Selected chip at selected controller */
+			chipstart = chipstop = chip;
+	}
+	debug("CTRLSTART=%d CTRLSTOP=%d CHIPSTART=%d CHIPSTOP=%d\n",
+	    ctrlstart, ctrlstop, chipstart, chipstop);
+	for (idx = ctrlstart; idx <= ctrlstop; idx++) {
+		err = is_ctrl_created(idx, &state);
+		if (err) {
+			error("Could not acquire ctrl#%d state. Cannot "
+			    "destroy controller.", idx);
+			return (EX_SOFTWARE);
+		}
+		if (state == 0) {
+			continue;
+		}
+		err = is_ctrl_running(idx, &state);
+		if (err) {
+			error(MSG_STATUSACQCTRL, idx);
+			return (EX_SOFTWARE);
+		}
+		if (state != 0) {
+			error(MSG_RUNNING, ctl);
+			return (EX_SOFTWARE);
+		}
+		if (opendev(&fd) != EX_OK)
+			return (EX_OSFILE);
+
+		for (idx2 = chipstart; idx2 <= chipstop; idx2++) {
+			err = is_chip_created(idx, idx2, &state);
+			if (err) {
+				error(MSG_STATUSACQCTRLCHIP, idx2, idx);
+				continue;
+			}
+			if (state == 0)
+				/* There is no such chip running */
+				continue;
+			chip_destroy.ctrl_num = idx;
+			chip_destroy.chip_num = idx2;
+			ioctl(fd, NANDSIM_DESTROY_CHIP,
+			    &chip_destroy);
+		}
+		/* If chip isn't explicitly specified -- destroy ctrl */
+		if (chip == 0xff) {
+			err = ioctl(fd, NANDSIM_DESTROY_CTRL, &idx);
+			if (err) {
+				error("Could not destroy ctrl#%d", idx);
+				continue;
+			}
+		}
+		close(fd);
+	}
+	return (err);
+}
+
+int
+main(int argc, char **argv)
+{
+	struct nandsim_command *cmdopts;
+	int retcode = 0;
+
+	if (argc < 2) {
+		cmdhelp(argc, argv);
+		retcode = EX_USAGE;
+	} else {
+		cmdopts = getcommand(argv[1]);
+		if (cmdopts != NULL && cmdopts->commandfunc != NULL) {
+			if (checkusage(argc, cmdopts->req_argc, argv) == 1) {
+				/* Print command specific usage */
+				printf("nandsim %s", cmdopts->usagestring);
+				return (EX_USAGE);
+			}
+			retcode = cmdopts->commandfunc(argc, argv);
+
+			if (retcode == EX_USAGE) {
+				/* Print command-specific usage */
+				printf("nandsim %s", cmdopts->usagestring);
+			} else if (retcode == EX_OSFILE) {
+				error("Could not open device file");
+			}
+
+		} else {
+			error("Unknown command!");
+			retcode = EX_USAGE;
+		}
+	}
+	return (retcode);
+}
+
+static int
+cmdhelp(int gargc __unused, char **gargv __unused)
+{
+	struct nandsim_command *opts;
+
+	printf("usage:  nandsim <command> [command params] [params]\n\n");
+
+	for (opts = commands; (opts != NULL) &&
+	    (opts->cmd_name != NULL); opts++)
+		printf("nandsim %s", opts->usagestring);
+
+	printf("\n");
+	return (EX_OK);
+}
+
+static void
+printchip(struct sim_chip *chip, uint8_t verbose)
+{
+
+	if (chip->created == 0)
+		return;
+	if (verbose > 0) {
+		printf("\n[Chip info]\n");
+		printf("num= %d\nctrl_num=%d\ndevice_id=%02x"
+		    "\tmanufacturer_id=%02x\ndevice_model=%s\nmanufacturer="
+		    "%s\ncol_addr_cycles=%d\nrow_addr_cycles=%d"
+		    "\npage_size=%d\noob_size=%d\npages_per_block=%d\n"
+		    "blocks_per_lun=%d\nluns=%d\n\nprog_time=%d\n"
+		    "erase_time=%d\nread_time=%d\n"
+		    "error_ratio=%d\nwear_level=%d\nwrite_protect=%c\n"
+		    "chip_width=%db\n", chip->num, chip->ctrl_num,
+		    chip->device_id, chip->manufact_id,chip->device_model,
+		    chip->manufacturer, chip->col_addr_cycles,
+		    chip->row_addr_cycles, chip->page_size,
+		    chip->oob_size, chip->pgs_per_blk, chip->blks_per_lun,
+		    chip->luns,chip->prog_time, chip->erase_time,
+		    chip->read_time, chip->error_ratio, chip->wear_level,
+		    (chip->is_wp == 0) ? 'N':'Y', chip->width);
+	} else {
+		printf("[Chip info]\n");
+		printf("\tnum=%d\n\tdevice_model=%s\n\tmanufacturer=%s\n"
+		    "\tpage_size=%d\n\twrite_protect=%s\n",
+		    chip->num, chip->device_model, chip->manufacturer,
+		    chip->page_size, (chip->is_wp == 0) ? "NO":"YES");
+	}
+}
+
+static void
+printctrl(struct sim_ctrl *ctrl)
+{
+	int i;
+
+	if (ctrl->created == 0) {
+		printf(MSG_NOCTRL "\n", ctrl->num);
+		return;
+	}
+	printf("\n[Controller info]\n");
+	printf("\trunning: %s\n", ctrl->running ? "yes" : "no");
+	printf("\tnum cs: %d\n", ctrl->num_cs);
+	printf("\tecc: %d\n", ctrl->ecc);
+	printf("\tlog_filename: %s\n", ctrl->filename);
+	printf("\tecc_layout:");
+	for (i = 0; i < MAX_ECC_BYTES; i++) {
+		if (ctrl->ecc_layout[i] == 0xffff)
+			break;
+		else
+			printf("%c%d", i%16 ? ' ' : '\n',
+			    ctrl->ecc_layout[i]);
+	}
+	printf("\n");
+}
+
+static int
+is_ctrl_running(int ctrl_no, int *running)
+{
+	struct sim_ctrl ctrl;
+	int err, fd;
+
+	ctrl.num = ctrl_no;
+	if (opendev(&fd) != EX_OK)
+		return (EX_OSFILE);
+
+	err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl);
+	if (err) {
+		error(MSG_STATUSACQCTRL, ctrl_no);
+		close(fd);
+		return (err);
+	}
+	*running = ctrl.running;
+	close(fd);
+	return (0);
+}
+
+static int
+is_ctrl_created(int ctrl_no, int *created)
+{
+	struct sim_ctrl ctrl;
+	int err, fd;
+
+	ctrl.num = ctrl_no;
+
+	if (opendev(&fd) != EX_OK)
+		return (EX_OSFILE);
+
+	err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl);
+	if (err) {
+		error("Could not acquire conf for ctrl#%d", ctrl_no);
+		close(fd);
+		return (err);
+	}
+	*created = ctrl.created;
+	close(fd);
+	return (0);
+}
+
+static int
+is_chip_created(int ctrl_no, int chip_no, int *created)
+{
+	struct sim_chip chip;
+	int err, fd;
+
+	chip.ctrl_num = ctrl_no;
+	chip.num = chip_no;
+
+	if (opendev(&fd) != EX_OK)
+		return (EX_OSFILE);
+
+	err = ioctl(fd, NANDSIM_STATUS_CHIP, &chip);
+	if (err) {
+		error("Could not acquire conf for chip#%d", chip_no);
+		close(fd);
+		return (err);
+	}
+	*created = chip.created;
+	close(fd);
+	return (0);
+}
+
+static int
+assert_chip_connected(int ctrl_no, int chip_no)
+{
+	int created, running;
+
+	if (is_ctrl_created(ctrl_no, &created))
+		return (0);
+
+	if (!created) {
+		error(MSG_NOCTRL, ctrl_no);
+		return (0);
+	}
+
+	if (is_chip_created(ctrl_no, chip_no, &created))
+		return (0);
+
+	if (!created) {
+		error(MSG_NOTCONFIGDCTRLCHIP, ctrl_no, chip_no);
+		return (0);
+	}
+
+	if (is_ctrl_running(ctrl_no, &running))
+		return (0);
+
+	if (!running) {
+		error(MSG_NOTRUNNING, ctrl_no);
+		return (0);
+	}
+
+	return (1);
+}
+
+static int
+printstats(int ctrlno, int chipno, uint32_t pageno, int cdevd)
+{
+	struct page_stat_io pstats;
+	struct block_stat_io bstats;
+	struct chip_param_io cparams;
+	uint32_t blkidx;
+	int err;
+
+	/* Gather information about chip */
+	err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams);
+
+	if (err) {
+		error("Could not acquire chip info for chip attached to cs#"
+		    "%d, ctrl#%d", chipno, ctrlno);
+		return (EX_SOFTWARE);
+	}
+
+	blkidx = (pageno / cparams.pages_per_block);
+	bstats.block_num = blkidx;
+
+	err = ioctl(cdevd, NAND_IO_BLOCK_STAT, &bstats);
+	if (err) {
+		error("Could not acquire block#%d statistics!", blkidx);
+		return (ENXIO);
+	}
+
+	printf("Block #%d erased: %d\n", blkidx, bstats.block_erased);
+	pstats.page_num = pageno;
+
+	err = ioctl(cdevd, NAND_IO_PAGE_STAT, &pstats);
+	if (err) {
+		error("Could not acquire page statistics!");
+		return (ENXIO);
+	}
+
+	debug("BLOCKIDX = %d PAGENO (REL. TO BLK) = %d\n", blkidx,
+	    pstats.page_num);
+
+	printf("Page#%d : reads:%d writes:%d \n\traw reads:%d raw writes:%d "
+	    "\n\tecc_succeeded:%d ecc_corrected:%d ecc_failed:%d\n",
+	    pstats.page_num, pstats.page_read, pstats.page_written,
+	    pstats.page_raw_read, pstats.page_raw_written,
+	    pstats.ecc_succeded, pstats.ecc_corrected, pstats.ecc_failed);
+	return (0);
+}


Property changes on: trunk/usr.sbin/nandsim/nandsim.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandsim/nandsim_cfgparse.c
===================================================================
--- trunk/usr.sbin/nandsim/nandsim_cfgparse.c	                        (rev 0)
+++ trunk/usr.sbin/nandsim/nandsim_cfgparse.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,960 @@
+/* $MidnightBSD$ */
+/*-
+ * 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 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: stable/10/usr.sbin/nandsim/nandsim_cfgparse.c 293290 2016-01-07 00:40:51Z bdrewery $");
+
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <dev/nand/nandsim.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "nandsim_cfgparse.h"
+
+#define warn(fmt, args...) do { \
+    printf("WARNING: " fmt "\n", ##args); } while (0)
+
+#define error(fmt, args...) do { \
+    printf("ERROR: " fmt "\n", ##args); } while (0)
+
+#define MSG_MANDATORYKEYMISSING "mandatory key \"%s\" value belonging to " \
+    "section \"%s\" is missing!\n"
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define debug(fmt, args...) do { \
+    printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0)
+#else
+#define debug(fmt, args...) do {} while(0)
+#endif
+
+#define STRBUFSIZ 2000
+
+/* Macros extracts type and type size */
+#define TYPE(x) ((x) & 0xf8)
+#define SIZE(x) (((x) & 0x07))
+
+/* Erase/Prog/Read time max and min values */
+#define DELAYTIME_MIN	10000
+#define DELAYTIME_MAX	10000000
+
+/* Structure holding configuration for controller. */
+static struct sim_ctrl ctrl_conf;
+/* Structure holding configuration for chip. */
+static struct sim_chip chip_conf;
+
+static struct nandsim_key nandsim_ctrl_keys[] = {
+	{"num_cs", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num_cs, 0},
+	{"ctrl_num", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num, 0},
+
+	{"ecc_layout", 1, VALUE_UINTARRAY | SIZE_16,
+	    (void *)&ctrl_conf.ecc_layout, MAX_ECC_BYTES},
+
+	{"filename", 0, VALUE_STRING,
+	    (void *)&ctrl_conf.filename, FILENAME_SIZE},
+
+	{"ecc", 0, VALUE_BOOL, (void *)&ctrl_conf.ecc, 0},
+	{NULL, 0, 0, NULL, 0},
+};
+
+static struct nandsim_key nandsim_chip_keys[] = {
+	{"chip_cs", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.num, 0},
+	{"chip_ctrl", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.ctrl_num,
+	    0},
+	{"device_id", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.device_id,
+	    0},
+	{"manufacturer_id", 1, VALUE_UINT | SIZE_8,
+	    (void *)&chip_conf.manufact_id, 0},
+	{"model", 0, VALUE_STRING, (void *)&chip_conf.device_model,
+	    DEV_MODEL_STR_SIZE},
+	{"manufacturer", 0, VALUE_STRING, (void *)&chip_conf.manufacturer,
+	    MAN_STR_SIZE},
+	{"page_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.page_size,
+	    0},
+	{"oob_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.oob_size,
+	    0},
+	{"pages_per_block", 1, VALUE_UINT | SIZE_32,
+	    (void *)&chip_conf.pgs_per_blk, 0},
+	{"blocks_per_lun", 1, VALUE_UINT | SIZE_32,
+	    (void *)&chip_conf.blks_per_lun, 0},
+	{"luns", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.luns, 0},
+	{"column_addr_cycle", 1,VALUE_UINT | SIZE_8,
+	    (void *)&chip_conf.col_addr_cycles, 0},
+	{"row_addr_cycle", 1, VALUE_UINT | SIZE_8,
+	    (void *)&chip_conf.row_addr_cycles, 0},
+	{"program_time", 0, VALUE_UINT | SIZE_32,
+	    (void *)&chip_conf.prog_time, 0},
+	{"erase_time", 0, VALUE_UINT | SIZE_32,
+	    (void *)&chip_conf.erase_time, 0},
+	{"read_time", 0, VALUE_UINT | SIZE_32,
+	    (void *)&chip_conf.read_time, 0},
+	{"width", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.width, 0},
+	{"wear_out", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.wear_level,
+	    0},
+	{"bad_block_map", 0, VALUE_UINTARRAY | SIZE_32,
+	    (void *)&chip_conf.bad_block_map, MAX_BAD_BLOCKS},
+	{NULL, 0, 0, NULL, 0},
+};
+
+static struct nandsim_section sections[] = {
+	{"ctrl", (struct nandsim_key *)&nandsim_ctrl_keys},
+	{"chip", (struct nandsim_key *)&nandsim_chip_keys},
+	{NULL, NULL},
+};
+
+static uint8_t logoutputtoint(char *, int *);
+static uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int);
+static uint8_t validate_ctrls(struct sim_ctrl *, int);
+static int configure_sim(const char *, struct rcfile *);
+static int create_ctrls(struct rcfile *, struct sim_ctrl **, int *);
+static int create_chips(struct rcfile *, struct sim_chip **, int *);
+static void destroy_ctrls(struct sim_ctrl *);
+static void destroy_chips(struct sim_chip *);
+static int validate_section_config(struct rcfile *, const char *, int);
+
+int
+convert_argint(char *arg, int *value)
+{
+
+	if (arg == NULL || value == NULL)
+		return (EINVAL);
+
+	errno = 0;
+	*value = (int)strtol(arg, NULL, 0);
+	if (*value == 0 && errno != 0) {
+		error("Cannot convert to number argument \'%s\'", arg);
+		return (EINVAL);
+	}
+	return (0);
+}
+
+int
+convert_arguint(char *arg, unsigned int *value)
+{
+
+	if (arg == NULL || value == NULL)
+		return (EINVAL);
+
+	errno = 0;
+	*value = (unsigned int)strtol(arg, NULL, 0);
+	if (*value == 0 && errno != 0) {
+		error("Cannot convert to number argument \'%s\'", arg);
+		return (EINVAL);
+	}
+	return (0);
+}
+
+/* Parse given ',' separated list of bytes into buffer. */
+int
+parse_intarray(char *array, int **buffer)
+{
+	char *tmp, *tmpstr, *origstr;
+	unsigned int currbufp = 0, i;
+	unsigned int count = 0, from  = 0, to = 0;
+
+	/* Remove square braces */
+	if (array[0] == '[')
+		array ++;
+	if (array[strlen(array)-1] == ']')
+		array[strlen(array)-1] = ',';
+
+	from = strlen(array);
+	origstr = (char *)malloc(sizeof(char) * from);
+	strcpy(origstr, array);
+
+	tmpstr = (char *)strtok(array, ",");
+	/* First loop checks for how big int array we need to allocate */
+	while (tmpstr != NULL) {
+		errno = 0;
+		if ((tmp = strchr(tmpstr, '-')) != NULL) {
+			*tmp = ' ';
+			if (convert_arguint(tmpstr, &from) ||
+			    convert_arguint(tmp, &to)) {
+				free(origstr);
+				return (EINVAL);
+			}
+
+			count += to - from + 1;
+		} else {
+			if (convert_arguint(tmpstr, &from)) {
+				free(origstr);
+				return (EINVAL);
+			}
+			count++;
+		}
+		tmpstr = (char *)strtok(NULL, ",");
+	}
+
+	if (count == 0)
+		goto out;
+
+	/* Allocate buffer of ints */
+	tmpstr = (char *)strtok(origstr, ",");
+	*buffer = malloc(count * sizeof(int));
+
+	/* Second loop is just inserting converted values into int array */
+	while (tmpstr != NULL) {
+		errno = 0;
+		if ((tmp = strchr(tmpstr, '-')) != NULL) {
+			*tmp = ' ';
+			from = strtol(tmpstr, NULL, 0);
+			to = strtol(tmp, NULL, 0);
+			tmpstr = strtok(NULL, ",");
+			for (i = from; i <= to; i ++)
+				(*buffer)[currbufp++] = i;
+			continue;
+		}
+		errno = 0;
+		from = (int)strtol(tmpstr, NULL, 0);
+		(*buffer)[currbufp++] = from;
+		tmpstr = (char *)strtok(NULL, ",");
+	}
+out:
+	free(origstr);
+	return (count);
+}
+
+/* Convert logoutput strings literals into appropriate ints. */
+static uint8_t
+logoutputtoint(char *logoutput, int *output)
+{
+	int out;
+
+	if (strcmp(logoutput, "file") == 0)
+		out = NANDSIM_OUTPUT_FILE;
+
+	else if (strcmp(logoutput, "console") == 0)
+		out = NANDSIM_OUTPUT_CONSOLE;
+
+	else if (strcmp(logoutput, "ram") == 0)
+		out = NANDSIM_OUTPUT_RAM;
+
+	else if (strcmp(logoutput, "none") == 0)
+		out = NANDSIM_OUTPUT_NONE;
+	else
+		out = -1;
+
+	*output = out;
+
+	if (out == -1)
+		return (EINVAL);
+	else
+		return (0);
+}
+
+static int
+configure_sim(const char *devfname, struct rcfile *f)
+{
+	struct sim_param sim_conf;
+	char buf[255];
+	int err, tmpv, fd;
+
+	err = rc_getint(f, "sim", 0, "log_level", &tmpv);
+
+	if (tmpv < 0 || tmpv > 255 || err) {
+		error("Bad log level specified (%d)\n", tmpv);
+		return (ENOTSUP);
+	} else
+		sim_conf.log_level = tmpv;
+
+	rc_getstring(f, "sim", 0, "log_output", 255, (char *)&buf);
+
+	tmpv = -1;
+	err = logoutputtoint((char *)&buf, &tmpv);
+	if (err) {
+		error("Log output specified in config file does not seem to "
+		    "be valid (%s)!", (char *)&buf);
+		return (ENOTSUP);
+	}
+
+	sim_conf.log_output = tmpv;
+
+	fd = open(devfname, O_RDWR);
+	if (fd == -1) {
+		error("could not open simulator device file (%s)!",
+		    devfname);
+		return (EX_OSFILE);
+	}
+
+	err = ioctl(fd, NANDSIM_SIM_PARAM, &sim_conf);
+	if (err) {
+		error("simulator parameters could not be modified: %s",
+		    strerror(errno));
+		close(fd);
+		return (ENXIO);
+	}
+
+	close(fd);
+	return (EX_OK);
+}
+
+static int
+create_ctrls(struct rcfile *f, struct sim_ctrl **ctrls, int *cnt)
+{
+	int count, i;
+	struct sim_ctrl *ctrlsptr;
+
+	count = rc_getsectionscount(f, "ctrl");
+	if (count > MAX_SIM_DEV) {
+		error("Too many CTRL sections specified(%d)", count);
+		return (ENOTSUP);
+	} else if (count == 0) {
+		error("No ctrl sections specified");
+		return (ENOENT);
+	}
+
+	ctrlsptr = (struct sim_ctrl *)malloc(sizeof(struct sim_ctrl) * count);
+	if (ctrlsptr == NULL) {
+		error("Could not allocate memory for ctrl configuration");
+		return (ENOMEM);
+	}
+
+	for (i = 0; i < count; i++) {
+		bzero((void *)&ctrl_conf, sizeof(ctrl_conf));
+
+		/*
+		 * ECC layout have to end up with 0xffff, so
+		 * we're filling buffer with 0xff. If ecc_layout is
+		 * defined in config file, values will be overridden.
+		 */
+		memset((void *)&ctrl_conf.ecc_layout, 0xff,
+		    sizeof(ctrl_conf.ecc_layout));
+
+		if (validate_section_config(f, "ctrl", i) != 0) {
+			free(ctrlsptr);
+			return (EINVAL);
+		}
+
+		if (parse_section(f, "ctrl", i) != 0) {
+			free(ctrlsptr);
+			return (EINVAL);
+		}
+
+		memcpy(&ctrlsptr[i], &ctrl_conf, sizeof(ctrl_conf));
+		/* Try to create ctrl with config parsed */
+		debug("NUM=%d\nNUM_CS=%d\nECC=%d\nFILENAME=%s\nECC_LAYOUT[0]"
+		    "=%d\nECC_LAYOUT[1]=%d\n\n",
+		    ctrlsptr[i].num, ctrlsptr[i].num_cs, ctrlsptr[i].ecc,
+		    ctrlsptr[i].filename, ctrlsptr[i].ecc_layout[0],
+		    ctrlsptr[i].ecc_layout[1]);
+	}
+	*cnt = count;
+	*ctrls = ctrlsptr;
+	return (0);
+}
+
+static void
+destroy_ctrls(struct sim_ctrl *ctrls)
+{
+
+	free(ctrls);
+}
+
+static int
+create_chips(struct rcfile *f, struct sim_chip **chips, int *cnt)
+{
+	struct sim_chip *chipsptr;
+	int count, i;
+
+	count = rc_getsectionscount(f, "chip");
+	if (count > (MAX_CTRL_CS * MAX_SIM_DEV)) {
+		error("Too many chip sections specified(%d)", count);
+		return (ENOTSUP);
+	} else if (count == 0) {
+		error("No chip sections specified");
+		return (ENOENT);
+	}
+
+	chipsptr = (struct sim_chip *)malloc(sizeof(struct sim_chip) * count);
+	if (chipsptr == NULL) {
+		error("Could not allocate memory for chip configuration");
+		return (ENOMEM);
+	}
+
+	for (i = 0; i < count; i++) {
+		bzero((void *)&chip_conf, sizeof(chip_conf));
+
+		/*
+		 * Bad block map have to end up with 0xffff, so
+		 * we're filling array with 0xff. If bad block map is
+		 * defined in config file, values will be overridden.
+		 */
+		memset((void *)&chip_conf.bad_block_map, 0xff,
+		    sizeof(chip_conf.bad_block_map));
+
+		if (validate_section_config(f, "chip", i) != 0) {
+			free(chipsptr);
+			return (EINVAL);
+		}
+
+		if (parse_section(f, "chip", i) != 0) {
+			free(chipsptr);
+			return (EINVAL);
+		}
+
+		memcpy(&chipsptr[i], &chip_conf, sizeof(chip_conf));
+
+		/* Try to create chip with config parsed */
+		debug("CHIP:\nNUM=%d\nCTRL_NUM=%d\nDEVID=%d\nMANID=%d\n"
+		    "PAGE_SZ=%d\nOOBSZ=%d\nREAD_T=%d\nDEVMODEL=%s\n"
+		    "MAN=%s\nCOLADDRCYCLES=%d\nROWADDRCYCLES=%d\nCHWIDTH=%d\n"
+		    "PGS/BLK=%d\nBLK/LUN=%d\nLUNS=%d\nERR_RATIO=%d\n"
+		    "WEARLEVEL=%d\nISWP=%d\n\n\n\n",
+		    chipsptr[i].num, chipsptr[i].ctrl_num,
+		    chipsptr[i].device_id, chipsptr[i].manufact_id,
+		    chipsptr[i].page_size, chipsptr[i].oob_size,
+		    chipsptr[i].read_time, chipsptr[i].device_model,
+		    chipsptr[i].manufacturer, chipsptr[i].col_addr_cycles,
+		    chipsptr[i].row_addr_cycles, chipsptr[i].width,
+		    chipsptr[i].pgs_per_blk, chipsptr[i].blks_per_lun,
+		    chipsptr[i].luns, chipsptr[i].error_ratio,
+		    chipsptr[i].wear_level, chipsptr[i].is_wp);
+	}
+	*cnt = count;
+	*chips = chipsptr;
+	return (0);
+}
+
+static void
+destroy_chips(struct sim_chip *chips)
+{
+
+	free(chips);
+}
+
+int
+parse_config(char *cfgfname, const char *devfname)
+{
+	int err = 0, fd;
+	unsigned int chipsectionscnt, ctrlsectionscnt, i;
+	struct rcfile *f;
+	struct sim_chip *chips;
+	struct sim_ctrl *ctrls;
+
+	err = rc_open(cfgfname, "r", &f);
+	if (err) {
+		error("could not open configuration file (%s)", cfgfname);
+		return (EX_NOINPUT);
+	}
+
+	/* First, try to configure simulator itself. */
+	if (configure_sim(devfname, f) != EX_OK) {
+		rc_close(f);
+		return (EINVAL);
+	}
+
+	debug("SIM CONFIGURED!\n");
+	/* Then create controllers' configs */
+	if (create_ctrls(f, &ctrls, &ctrlsectionscnt) != 0) {
+		rc_close(f);
+		return (ENXIO);
+	}
+	debug("CTRLS CONFIG READ!\n");
+
+	/* Then create chips' configs */
+	if (create_chips(f, &chips, &chipsectionscnt) != 0) {
+		destroy_ctrls(ctrls);
+		rc_close(f);
+		return (ENXIO);
+	}
+	debug("CHIPS CONFIG READ!\n");
+
+	if (validate_ctrls(ctrls, ctrlsectionscnt) != 0) {
+		destroy_ctrls(ctrls);
+		destroy_chips(chips);
+		rc_close(f);
+		return (EX_SOFTWARE);
+	}
+	if (validate_chips(chips, chipsectionscnt, ctrls,
+	    ctrlsectionscnt) != 0) {
+		destroy_ctrls(ctrls);
+		destroy_chips(chips);
+		rc_close(f);
+		return (EX_SOFTWARE);
+	}
+
+	/* Open device */
+	fd = open(devfname, O_RDWR);
+	if (fd == -1) {
+		error("could not open simulator device file (%s)!",
+		    devfname);
+		rc_close(f);
+		destroy_chips(chips);
+		destroy_ctrls(ctrls);
+		return (EX_OSFILE);
+	}
+
+	debug("SIM CONFIG STARTED!\n");
+
+	/* At this stage, both ctrls' and chips' configs should be valid */
+	for (i = 0; i < ctrlsectionscnt; i++) {
+		err = ioctl(fd, NANDSIM_CREATE_CTRL, &ctrls[i]);
+		if (err) {
+			if (err == EEXIST)
+				error("Controller#%d already created\n",
+				    ctrls[i].num);
+			else if (err == EINVAL)
+				error("Incorrect controler number (%d)\n",
+				    ctrls[i].num);
+			else
+				error("Could not created controller#%d\n",
+				    ctrls[i].num);
+			/* Errors during controller creation stops parsing */
+			close(fd);
+			rc_close(f);
+			destroy_ctrls(ctrls);
+			destroy_chips(chips);
+			return (ENXIO);
+		}
+		debug("CTRL#%d CONFIG STARTED!\n", i);
+	}
+
+	for (i = 0; i < chipsectionscnt; i++) {
+		err = ioctl(fd, NANDSIM_CREATE_CHIP, &chips[i]);
+		if (err) {
+			if (err == EEXIST)
+				error("Chip#%d for controller#%d already "
+				    "created\n", chips[i].num,
+				    chips[i].ctrl_num);
+			else if (err == EINVAL)
+				error("Incorrect chip number (%d:%d)\n",
+				    chips[i].num, chips[i].ctrl_num);
+			else
+				error("Could not create chip (%d:%d)\n",
+				    chips[i].num, chips[i].ctrl_num);
+			error("Could not start chip#%d\n", i);
+			destroy_chips(chips);
+			destroy_ctrls(ctrls);
+			close(fd);
+			rc_close(f);
+			return (ENXIO);
+		}
+	}
+	debug("CHIPS CONFIG STARTED!\n");
+
+	close(fd);
+	rc_close(f);
+	destroy_chips(chips);
+	destroy_ctrls(ctrls);
+	return (0);
+}
+
+/*
+ * Function tries to get appropriate value for given key, convert it to
+ * array of ints (of given size), and perform all the necessary checks and
+ * conversions.
+ */
+static int
+get_argument_intarray(const char *sect_name, int sectno,
+    struct nandsim_key *key, struct rcfile *f)
+{
+	char strbuf[STRBUFSIZ];
+	int *intbuf;
+	int getres;
+	uint32_t cnt, i = 0;
+
+	getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
+	    (char *)&strbuf);
+
+	if (getres != 0) {
+		if (key->mandatory != 0) {
+			error(MSG_MANDATORYKEYMISSING, key->keyname,
+			    sect_name);
+			return (EINVAL);
+		} else
+			/* Non-mandatory key, not present -- skip */
+			return (0);
+	}
+	cnt = parse_intarray((char *)&strbuf, &intbuf);
+	cnt = (cnt <= key->maxlength) ? cnt : key->maxlength;
+
+	for (i = 0; i < cnt; i++) {
+		if (SIZE(key->valuetype) == SIZE_8)
+			*((uint8_t *)(key->field) + i) =
+			    (uint8_t)intbuf[i];
+		else if (SIZE(key->valuetype) == SIZE_16)
+			*((uint16_t *)(key->field) + i) =
+			    (uint16_t)intbuf[i];
+		else
+			*((uint32_t *)(key->field) + i) =
+			    (uint32_t)intbuf[i];
+	}
+	free(intbuf);
+	return (0);
+}
+
+/*
+ *  Function tries to get appropriate value for given key, convert it to
+ *  int of certain length.
+ */
+static int
+get_argument_int(const char *sect_name, int sectno, struct nandsim_key *key,
+    struct rcfile *f)
+{
+	int getres;
+	uint32_t val;
+
+	getres = rc_getint(f, sect_name, sectno, key->keyname, &val);
+	if (getres != 0) {
+
+		if (key->mandatory != 0) {
+			error(MSG_MANDATORYKEYMISSING, key->keyname,
+			    sect_name);
+
+			return (EINVAL);
+		} else
+			/* Non-mandatory key, not present -- skip */
+			return (0);
+	}
+	if (SIZE(key->valuetype) == SIZE_8)
+		*(uint8_t *)(key->field) = (uint8_t)val;
+	else if (SIZE(key->valuetype) == SIZE_16)
+		*(uint16_t *)(key->field) = (uint16_t)val;
+	else
+		*(uint32_t *)(key->field) = (uint32_t)val;
+	return (0);
+}
+
+/* Function tries to get string value for given key */
+static int
+get_argument_string(const char *sect_name, int sectno,
+    struct nandsim_key *key, struct rcfile *f)
+{
+	char strbuf[STRBUFSIZ];
+	int getres;
+
+	getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
+	    strbuf);
+
+	if (getres != 0) {
+		if (key->mandatory != 0) {
+			error(MSG_MANDATORYKEYMISSING, key->keyname,
+			    sect_name);
+			return (1);
+		} else
+			/* Non-mandatory key, not present -- skip */
+			return (0);
+	}
+	strncpy(key->field, (char *)&strbuf, (size_t)(key->maxlength - 1));
+	return (0);
+}
+
+/* Function tries to get on/off value for given key */
+static int
+get_argument_bool(const char *sect_name, int sectno, struct nandsim_key *key,
+    struct rcfile *f)
+{
+	int getres, val;
+
+	getres = rc_getbool(f, sect_name, sectno, key->keyname, &val);
+	if (getres != 0) {
+		if (key->mandatory != 0) {
+			error(MSG_MANDATORYKEYMISSING, key->keyname,
+			    sect_name);
+			return (1);
+		} else
+			/* Non-mandatory key, not present -- skip */
+			return (0);
+	}
+	*(uint8_t *)key->field = (uint8_t)val;
+	return (0);
+}
+
+int
+parse_section(struct rcfile *f, const char *sect_name, int sectno)
+{
+	struct nandsim_key *key;
+	struct nandsim_section *sect = (struct nandsim_section *)§ions;
+	int getres = 0;
+
+	while (1) {
+		if (sect == NULL)
+			return (EINVAL);
+
+		if (strcmp(sect->name, sect_name) == 0)
+			break;
+		else
+			sect++;
+	}
+	key = sect->keys;
+	do {
+		debug("->Section: %s, Key: %s, type: %d, size: %d",
+		    sect_name, key->keyname, TYPE(key->valuetype),
+		    SIZE(key->valuetype)/2);
+
+		switch (TYPE(key->valuetype)) {
+		case VALUE_UINT:
+			/* Single int value */
+			getres = get_argument_int(sect_name, sectno, key, f);
+
+			if (getres != 0)
+				return (getres);
+
+			break;
+		case VALUE_UINTARRAY:
+			/* Array of ints */
+			getres = get_argument_intarray(sect_name,
+			    sectno, key, f);
+
+			if (getres != 0)
+				return (getres);
+
+			break;
+		case VALUE_STRING:
+			/* Array of chars */
+			getres = get_argument_string(sect_name, sectno, key,
+			    f);
+
+			if (getres != 0)
+				return (getres);
+
+			break;
+		case VALUE_BOOL:
+			/* Boolean value (true/false/on/off/yes/no) */
+			getres = get_argument_bool(sect_name, sectno, key,
+			    f);
+
+			if (getres != 0)
+				return (getres);
+
+			break;
+		}
+	} while ((++key)->keyname != NULL);
+
+	return (0);
+}
+
+static uint8_t
+validate_chips(struct sim_chip *chips, int chipcnt,
+    struct sim_ctrl *ctrls, int ctrlcnt)
+{
+	int cchipcnt, i, width, j, id, max;
+
+	cchipcnt = chipcnt;
+	for (chipcnt -= 1; chipcnt >= 0; chipcnt--) {
+		if (chips[chipcnt].num >= MAX_CTRL_CS) {
+			error("chip no. too high (%d)!!\n",
+			    chips[chipcnt].num);
+			return (EINVAL);
+		}
+
+		if (chips[chipcnt].ctrl_num >= MAX_SIM_DEV) {
+			error("controller no. too high (%d)!!\n",
+			    chips[chipcnt].ctrl_num);
+			return (EINVAL);
+		}
+
+		if (chips[chipcnt].width != 8 &&
+		    chips[chipcnt].width != 16) {
+			error("invalid width:%d for chip#%d",
+			    chips[chipcnt].width, chips[chipcnt].num);
+			return (EINVAL);
+		}
+
+		/* Check if page size is > 512 and if its power of 2 */
+		if (chips[chipcnt].page_size < 512 ||
+		    (chips[chipcnt].page_size &
+		    (chips[chipcnt].page_size - 1)) != 0) {
+			error("invalid page size:%d for chip#%d at ctrl#%d!!"
+			    "\n", chips[chipcnt].page_size,
+			    chips[chipcnt].num,
+			    chips[chipcnt].ctrl_num);
+			return (EINVAL);
+		}
+
+		/* Check if controller no. ctrl_num is configured */
+		for (i = 0, id = -1; i < ctrlcnt && id == -1; i++)
+			if (ctrls[i].num == chips[chipcnt].ctrl_num)
+				id = i;
+
+		if (i == ctrlcnt && id == -1) {
+			error("Missing configuration for controller %d"
+			    " (at least one chip is connected to it)",
+			    chips[chipcnt].ctrl_num);
+			return (EINVAL);
+		} else {
+			/*
+			 * Controller is configured -> check oob_size
+			 * validity
+			 */
+			i = 0;
+			max = ctrls[id].ecc_layout[0];
+			while (i < MAX_ECC_BYTES &&
+			    ctrls[id].ecc_layout[i] != 0xffff) {
+
+				if (ctrls[id].ecc_layout[i] > max)
+					max = ctrls[id].ecc_layout[i];
+				i++;
+			}
+
+			if (chips[chipcnt].oob_size < (unsigned)i) {
+				error("OOB size for chip#%d at ctrl#%d is "
+				    "smaller than ecc layout length!",
+				    chips[chipcnt].num,
+				    chips[chipcnt].ctrl_num);
+				exit(EINVAL);
+			}
+
+			if (chips[chipcnt].oob_size < (unsigned)max) {
+				error("OOB size for chip#%d at ctrl#%d is "
+				    "smaller than maximal ecc position in "
+				    "defined layout!", chips[chipcnt].num,
+				    chips[chipcnt].ctrl_num);
+				exit(EINVAL);
+			}
+
+
+		}
+
+		if ((chips[chipcnt].erase_time < DELAYTIME_MIN ||
+		    chips[chipcnt].erase_time > DELAYTIME_MAX) &&
+		    chips[chipcnt].erase_time != 0) {
+			error("Invalid erase time value for chip#%d at "
+			    "ctrl#%d",
+			    chips[chipcnt].num,
+			    chips[chipcnt].ctrl_num);
+			return (EINVAL);
+		}
+
+		if ((chips[chipcnt].prog_time < DELAYTIME_MIN ||
+		    chips[chipcnt].prog_time > DELAYTIME_MAX) &&
+		    chips[chipcnt].prog_time != 0) {
+			error("Invalid prog time value for chip#%d at "
+			    "ctr#%d!",
+			    chips[chipcnt].num,
+			    chips[chipcnt].ctrl_num);
+			return (EINVAL);
+		}
+
+		if ((chips[chipcnt].read_time < DELAYTIME_MIN ||
+		    chips[chipcnt].read_time > DELAYTIME_MAX) &&
+		    chips[chipcnt].read_time != 0) {
+			error("Invalid read time value for chip#%d at "
+			    "ctrl#%d!",
+			    chips[chipcnt].num,
+			    chips[chipcnt].ctrl_num);
+			return (EINVAL);
+		}
+	}
+	/* Check if chips attached to the same controller, have same width */
+	for (i = 0; i < ctrlcnt; i++) {
+		width = -1;
+		for (j = 0; j < cchipcnt; j++) {
+			if (chips[j].ctrl_num == i) {
+				if (width == -1) {
+					width = chips[j].width;
+				} else {
+					if (width != chips[j].width) {
+						error("Chips attached to "
+						    "ctrl#%d have different "
+						    "widths!\n", i);
+						return (EINVAL);
+					}
+				}
+			}
+		}
+	}
+
+	return (0);
+}
+
+static uint8_t
+validate_ctrls(struct sim_ctrl *ctrl, int ctrlcnt)
+{
+	for (ctrlcnt -= 1; ctrlcnt >= 0; ctrlcnt--) {
+		if (ctrl[ctrlcnt].num > MAX_SIM_DEV) {
+			error("Controller no. too high (%d)!!\n",
+			    ctrl[ctrlcnt].num);
+			return (EINVAL);
+		}
+		if (ctrl[ctrlcnt].num_cs > MAX_CTRL_CS) {
+			error("Too many CS (%d)!!\n", ctrl[ctrlcnt].num_cs);
+			return (EINVAL);
+		}
+		if (ctrl[ctrlcnt].ecc != 0 && ctrl[ctrlcnt].ecc != 1) {
+			error("ECC is set to neither 0 nor 1 !\n");
+			return (EINVAL);
+		}
+	}
+
+	return (0);
+}
+
+static int validate_section_config(struct rcfile *f, const char *sect_name,
+    int sectno)
+{
+	struct nandsim_key *key;
+	struct nandsim_section *sect;
+	char **keys_tbl;
+	int i, match;
+
+	for (match = 0, sect = (struct nandsim_section *)§ions;
+	    sect != NULL; sect++) {
+		if (strcmp(sect->name, sect_name) == 0) {
+			match = 1;
+			break;
+		}
+	}
+
+	if (match == 0)
+		return (EINVAL);
+
+	keys_tbl = rc_getkeys(f, sect_name, sectno);
+	if (keys_tbl == NULL)
+		return (ENOMEM);
+
+	for (i = 0; keys_tbl[i] != NULL; i++) {
+		key = sect->keys;
+		match = 0;
+		do {
+			if (strcmp(keys_tbl[i], key->keyname) == 0) {
+				match = 1;
+				break;
+			}
+		} while ((++key)->keyname != NULL);
+
+		if (match == 0) {
+			error("Invalid key in config file: %s\n", keys_tbl[i]);
+			free(keys_tbl);
+			return (EINVAL);
+		}
+	}
+
+	free(keys_tbl);
+	return (0);
+}


Property changes on: trunk/usr.sbin/nandsim/nandsim_cfgparse.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandsim/nandsim_cfgparse.h
===================================================================
--- trunk/usr.sbin/nandsim/nandsim_cfgparse.h	                        (rev 0)
+++ trunk/usr.sbin/nandsim/nandsim_cfgparse.h	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,87 @@
+/* $MidnightBSD$ */
+/*-
+ * 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 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: stable/10/usr.sbin/nandsim/nandsim_cfgparse.h 235537 2012-05-17 10:11:18Z gber $
+ */
+
+#ifndef _NANDSIM_CONFPARSER_H_
+#define _NANDSIM_CONFPARSER_H_
+
+#define VALUE_UINT	0x08
+#define VALUE_INT	0x10
+#define VALUE_UINTARRAY	0x18
+#define VALUE_INTARRAY	0x20
+#define VALUE_STRING	0x28
+#define VALUE_CHAR	0x40
+#define VALUE_BOOL	0x48
+
+#define SIZE_8	0x01
+#define SIZE_16	0x02
+#define SIZE_32	0x04
+
+#include "nandsim_rcfile.h"
+
+/*
+ * keyname	= name of a key,
+ * mandatory	= is key mandatory in section belonging to, 0=false 1=true
+ * valuetype	= what kind of value is assigned to that key, e.g.
+ *		  VALUE_UINT | SIZE_8 -- unsigned uint size 8 bits;
+ *		  VALUE_UINTARRAY | SIZE_8 -- array of uints 8-bit long;
+ *		  VALUE_BOOL -- 'on', 'off','true','false','yes' or 'no'
+ *		  literals;
+ *		  VALUE_STRING -- strings
+ * field	= ptr to the field that should hold value for parsed value
+ * maxlength	= contains maximum length of an array (used only with either
+ *		  VALUE_STRING or VALUE_(U)INTARRAY value types.
+ */
+struct nandsim_key {
+	const char	*keyname;
+	uint8_t		mandatory;
+	uint8_t		valuetype;
+	void		*field;
+	uint32_t	maxlength;
+};
+struct nandsim_section {
+	const char		*name;
+	struct nandsim_key	*keys;
+};
+
+struct nandsim_config {
+	struct sim_param	**simparams;
+	struct sim_chip		**simchips;
+	struct sim_ctrl		**simctrls;
+	int			chipcnt;
+	int			ctrlcnt;
+};
+
+int parse_intarray(char *, int **);
+int parse_config(char *, const char *);
+int parse_section(struct rcfile *, const char *, int);
+int compare_configs(struct nandsim_config *, struct nandsim_config *);
+int convert_argint(char *, int *);
+int convert_arguint(char *, unsigned int *);
+
+#endif /* _NANDSIM_CONFPARSER_H_ */


Property changes on: trunk/usr.sbin/nandsim/nandsim_cfgparse.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandsim/nandsim_rcfile.c
===================================================================
--- trunk/usr.sbin/nandsim/nandsim_rcfile.c	                        (rev 0)
+++ trunk/usr.sbin/nandsim/nandsim_rcfile.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,441 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (c) 1999, Boris Popov
+ * 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.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
+ *
+ * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/nandsim/nandsim_rcfile.c 235537 2012-05-17 10:11:18Z gber $");
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include "nandsim_rcfile.h"
+
+SLIST_HEAD(rcfile_head, rcfile);
+static struct rcfile_head pf_head = {NULL};
+static struct rcsection *rc_findsect(struct rcfile *rcp,
+    const char *sectname, int sect_id);
+static struct rcsection *rc_addsect(struct rcfile *rcp,
+    const char *sectname);
+static int rc_sect_free(struct rcsection *rsp);
+static struct rckey *rc_sect_findkey(struct rcsection *rsp,
+    const char *keyname);
+static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name,
+    char *value);
+static void rc_key_free(struct rckey *p);
+static void rc_parse(struct rcfile *rcp);
+
+static struct rcfile* rc_find(const char *filename);
+
+/*
+ * open rcfile and load its content, if already open - return previous handle
+ */
+int
+rc_open(const char *filename, const char *mode,struct rcfile **rcfile)
+{
+	struct rcfile *rcp;
+	FILE *f;
+	rcp = rc_find(filename);
+	if (rcp) {
+		*rcfile = rcp;
+		return (0);
+	}
+	f = fopen (filename, mode);
+	if (f == NULL)
+		return errno;
+	rcp = malloc(sizeof(struct rcfile));
+	if (rcp == NULL) {
+		fclose(f);
+		return ENOMEM;
+	}
+	bzero(rcp, sizeof(struct rcfile));
+	rcp->rf_name = strdup(filename);
+	rcp->rf_f = f;
+	SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+	rc_parse(rcp);
+	*rcfile = rcp;
+	return (0);
+}
+
+int
+rc_close(struct rcfile *rcp)
+{
+	struct rcsection *p,*n;
+
+	fclose(rcp->rf_f);
+	for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
+		n = p;
+		p = SLIST_NEXT(p,rs_next);
+		rc_sect_free(n);
+	}
+	free(rcp->rf_name);
+	SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
+	free(rcp);
+	return (0);
+}
+
+static struct rcfile*
+rc_find(const char *filename)
+{
+	struct rcfile *p;
+
+	SLIST_FOREACH(p, &pf_head, rf_next)
+		if (strcmp (filename, p->rf_name) == 0)
+			return (p);
+	return (0);
+}
+
+/* Find section with given name and id */
+static struct rcsection *
+rc_findsect(struct rcfile *rcp, const char *sectname, int sect_id)
+{
+	struct rcsection *p;
+
+	SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
+		if (strcmp(p->rs_name, sectname) == 0 && p->rs_id == sect_id)
+			return (p);
+	return (NULL);
+}
+
+static struct rcsection *
+rc_addsect(struct rcfile *rcp, const char *sectname)
+{
+	struct rcsection *p;
+	int id = 0;
+	p = rc_findsect(rcp, sectname, 0);
+	if (p) {
+		/*
+		 * If section with that name already exists -- add one more,
+		 * same named, but with different id (higher by one)
+		 */
+		while (p != NULL) {
+			id = p->rs_id + 1;
+			p = rc_findsect(rcp, sectname, id);
+		}
+	}
+	p = malloc(sizeof(*p));
+	if (!p)
+		return (NULL);
+	p->rs_name = strdup(sectname);
+	p->rs_id = id;
+	SLIST_INIT(&p->rs_keys);
+	SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
+	return (p);
+}
+
+static int
+rc_sect_free(struct rcsection *rsp)
+{
+	struct rckey *p,*n;
+
+	for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
+		n = p;
+		p = SLIST_NEXT(p,rk_next);
+		rc_key_free(n);
+	}
+	free(rsp->rs_name);
+	free(rsp);
+	return (0);
+}
+
+static struct rckey *
+rc_sect_findkey(struct rcsection *rsp, const char *keyname)
+{
+	struct rckey *p;
+
+	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
+		if (strcmp(p->rk_name, keyname)==0)
+			return (p);
+	return (NULL);
+}
+
+static struct rckey *
+rc_sect_addkey(struct rcsection *rsp, const char *name, char *value)
+{
+	struct rckey *p;
+	p = rc_sect_findkey(rsp, name);
+	if (p) {
+		free(p->rk_value);
+	} else {
+		p = malloc(sizeof(*p));
+		if (!p)
+			return (NULL);
+		SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
+		p->rk_name = strdup(name);
+	}
+	p->rk_value = value ? strdup(value) : strdup("");
+	return (p);
+}
+
+static void
+rc_key_free(struct rckey *p)
+{
+	free(p->rk_value);
+	free(p->rk_name);
+	free(p);
+}
+
+enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
+
+static void
+rc_parse(struct rcfile *rcp)
+{
+	FILE *f = rcp->rf_f;
+	int state = stNewLine, c;
+	struct rcsection *rsp = NULL;
+	struct rckey *rkp = NULL;
+	char buf[2048];
+	char *next = buf, *last = &buf[sizeof(buf)-1];
+
+	while ((c = getc (f)) != EOF) {
+		if (c == '\r')
+			continue;
+		if (state == stNewLine) {
+			next = buf;
+			if (isspace(c))
+				continue;	/* skip leading junk */
+			if (c == '[') {
+				state = stHeader;
+				rsp = NULL;
+				continue;
+			}
+			if (c == '#' || c == ';') {
+				state = stSkipToEOL;
+			} else {		/* something meaningful */
+				state = stGetKey;
+			}
+		}
+		if (state == stSkipToEOL || next == last) {/* ignore long lines */
+			if (c == '\n') {
+				state = stNewLine;
+				next = buf;
+			}
+			continue;
+		}
+		if (state == stHeader) {
+			if (c == ']') {
+				*next = 0;
+				next = buf;
+				rsp = rc_addsect(rcp, buf);
+				state = stSkipToEOL;
+			} else
+				*next++ = c;
+			continue;
+		}
+		if (state == stGetKey) {
+			if (c == ' ' || c == '\t')/* side effect: 'key name='*/
+				continue;	  /* become 'keyname='	     */
+			if (c == '\n') {	  /* silently ignore ... */
+				state = stNewLine;
+				continue;
+			}
+			if (c != '=') {
+				*next++ = c;
+				continue;
+			}
+			*next = 0;
+			if (rsp == NULL) {
+				fprintf(stderr, "Key '%s' defined before "
+				    "section\n", buf);
+				state = stSkipToEOL;
+				continue;
+			}
+			rkp = rc_sect_addkey(rsp, buf, NULL);
+			next = buf;
+			state = stGetValue;
+			continue;
+		}
+		/* only stGetValue left */
+		if (state != stGetValue) {
+			fprintf(stderr, "Well, I can't parse file "
+			    "'%s'\n",rcp->rf_name);
+			state = stSkipToEOL;
+		}
+		if (c != '\n') {
+			*next++ = c;
+			continue;
+		}
+		*next = 0;
+		rkp->rk_value = strdup(buf);
+		state = stNewLine;
+		rkp = NULL;
+	}	/* while */
+	if (c == EOF && state == stGetValue) {
+		*next = 0;
+		rkp->rk_value = strdup(buf);
+	}
+}
+
+int
+rc_getstringptr(struct rcfile *rcp, const char *section, int sect_id,
+    const char *key, char **dest)
+{
+	struct rcsection *rsp;
+	struct rckey *rkp;
+
+	*dest = NULL;
+	rsp = rc_findsect(rcp, section, sect_id);
+	if (!rsp)
+		return (ENOENT);
+	rkp = rc_sect_findkey(rsp,key);
+	if (!rkp)
+		return (ENOENT);
+	*dest = rkp->rk_value;
+	return (0);
+}
+
+int
+rc_getstring(struct rcfile *rcp, const char *section, int sect_id,
+    const char *key, unsigned int maxlen, char *dest)
+{
+	char *value;
+	int error;
+
+	error = rc_getstringptr(rcp, section, sect_id, key, &value);
+	if (error)
+		return (error);
+	if (strlen(value) >= maxlen) {
+		fprintf(stderr, "line too long for key '%s' in section '%s',"
+		    "max = %d\n",key, section, maxlen);
+		return (EINVAL);
+	}
+	strcpy(dest,value);
+	return (0);
+}
+
+int
+rc_getint(struct rcfile *rcp, const char *section, int sect_id,
+    const char *key, int *value)
+{
+	struct rcsection *rsp;
+	struct rckey *rkp;
+
+	rsp = rc_findsect(rcp, section, sect_id);
+	if (!rsp)
+		return (ENOENT);
+	rkp = rc_sect_findkey(rsp,key);
+	if (!rkp)
+		return (ENOENT);
+	errno = 0;
+	*value = strtol(rkp->rk_value,NULL,0);
+	if (errno) {
+		fprintf(stderr, "invalid int value '%s' for key '%s' in "
+		    "section '%s'\n",rkp->rk_value,key,section);
+		return (errno);
+	}
+	return (0);
+}
+
+/*
+ * 1,yes,true
+ * 0,no,false
+ */
+int
+rc_getbool(struct rcfile *rcp, const char *section, int sect_id,
+    const char *key, int *value)
+{
+	struct rcsection *rsp;
+	struct rckey *rkp;
+	char *p;
+
+	rsp = rc_findsect(rcp, section, sect_id);
+	if (!rsp)
+		return (ENOENT);
+	rkp = rc_sect_findkey(rsp,key);
+	if (!rkp)
+		return (ENOENT);
+	p = rkp->rk_value;
+	while (*p && isspace(*p)) p++;
+	if (*p == '0' || strcasecmp(p,"no") == 0 ||
+	    strcasecmp(p, "false") == 0 ||
+	    strcasecmp(p, "off") == 0) {
+		*value = 0;
+		return (0);
+	}
+	if (*p == '1' || strcasecmp(p,"yes") == 0 ||
+	    strcasecmp(p, "true") == 0 ||
+	    strcasecmp(p, "on") == 0) {
+		*value = 1;
+		return (0);
+	}
+	fprintf(stderr, "invalid boolean value '%s' for key '%s' in section "
+	    "'%s' \n",p, key, section);
+	return (EINVAL);
+}
+
+/* Count how many sections with given name exists in configuration. */
+int rc_getsectionscount(struct rcfile *f, const char *sectname)
+{
+	struct rcsection *p;
+	int count = 0;
+
+	p = rc_findsect(f, sectname, 0);
+	if (p) {
+		while (p != NULL) {
+			count = p->rs_id + 1;
+			p = rc_findsect(f, sectname, count);
+		}
+		return (count);
+	} else
+		return (0);
+}
+
+char **
+rc_getkeys(struct rcfile *rcp, const char *sectname, int sect_id)
+{
+	struct rcsection *rsp;
+	struct rckey *p;
+	char **names_tbl;
+	int i = 0, count = 0;
+
+	rsp = rc_findsect(rcp, sectname, sect_id);
+	if (rsp == NULL)
+		return (NULL);
+
+	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
+		count++;
+
+	names_tbl = malloc(sizeof(char *) * (count + 1));
+	if (names_tbl == NULL)
+		return (NULL);
+
+	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
+		names_tbl[i++] = p->rk_name;
+
+	names_tbl[i] = NULL;
+	return (names_tbl);
+}
+


Property changes on: trunk/usr.sbin/nandsim/nandsim_rcfile.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandsim/nandsim_rcfile.h
===================================================================
--- trunk/usr.sbin/nandsim/nandsim_rcfile.h	                        (rev 0)
+++ trunk/usr.sbin/nandsim/nandsim_rcfile.h	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,71 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (c) 1999, Boris Popov
+ * 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.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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: stable/10/usr.sbin/nandsim/nandsim_rcfile.h 235537 2012-05-17 10:11:18Z gber $
+ *
+ * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp
+ */
+
+#ifndef _SIMRC_H_
+#define _SIMRC_H_
+
+#include <sys/queue.h>
+
+struct rckey {
+	SLIST_ENTRY(rckey)	rk_next;
+	char			*rk_name;	/* key name */
+	char			*rk_value;	/* key value */
+};
+
+struct rcsection {
+	SLIST_ENTRY(rcsection)	rs_next;
+	SLIST_HEAD(rckey_head,rckey) rs_keys;	/* key list */
+	char			*rs_name;	/* section name */
+	int			rs_id;		/* allow few same named */
+};
+
+struct rcfile {
+	SLIST_ENTRY(rcfile)	rf_next;
+	SLIST_HEAD(rcsec_head, rcsection) rf_sect;	/* sections list */
+	char			*rf_name;		/* file name */
+	FILE			*rf_f;			/* file desc */
+};
+
+int rc_open(const char *, const char *,struct rcfile **);
+int rc_close(struct rcfile *);
+int rc_getstringptr(struct rcfile *, const char *, int, const char *,
+    char **);
+int rc_getstring(struct rcfile *, const char *, int, const char *,
+    unsigned int, char *);
+int rc_getint(struct rcfile *, const char *, int, const char *, int *);
+int rc_getbool(struct rcfile *, const char *, int, const char *, int *);
+int rc_getsectionscount(struct rcfile *, const char *);
+char **rc_getkeys(struct rcfile *, const char *, int);
+
+#endif /* _SIMRC_H_ */


Property changes on: trunk/usr.sbin/nandsim/nandsim_rcfile.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandsim/sample.conf
===================================================================
--- trunk/usr.sbin/nandsim/sample.conf	                        (rev 0)
+++ trunk/usr.sbin/nandsim/sample.conf	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,175 @@
+#-
+# 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.
+#
+# $FreeBSD: stable/10/usr.sbin/nandsim/sample.conf 235537 2012-05-17 10:11:18Z gber $
+# $MidnightBSD$
+
+#
+# Sample NANDsim configuration file.
+#
+
+#############################################################################
+#
+# [sim] General (common) simulator configuration section.
+#
+[sim]
+# log_level=0..255
+log_level=11
+
+# log_output=[none, console, ram, file]
+#
+# When log_output=file is specified, each [ctrl] section must have a
+# corresponding 'log_filename' field provided, which specifies log file name
+# to be used.
+log_output=none
+
+#############################################################################
+#
+# [ctrl] Controller configuration section.
+#
+# There can be a number of controllers defined for simulation, each has a
+# dedicated [ctrl] section. With a given controller there are associated
+# subordinate NAND chips, which are tied to chip select lines.
+#
+[ctrl]
+# The number of this controller.
+# ctrl_num=0..3
+ctrl_num=0
+
+# The number of chip selects available at this controller.
+# num_cs=1..4
+num_cs=1
+
+# ECC enable flag.
+# ecc=[on|off]
+ecc=on
+
+# ECC layout. This is the list of byte offsets within OOB area, which comprise
+# the ECC contents set.
+#
+# ecc_layout=[byte1, byte2-byte3, ..byten]
+ecc_layout=[0-53]
+
+# Absolute path to the log file for this controller.
+#log_filename=/var/log/nandsim-ctl0.log
+
+
+#############################################################################
+#
+# [chip] Chip configuration section.
+#
+# There can be a number of individual NAND chip devices defined for
+# simulation, and each has a dedicated [chip] section.
+#
+# A particular chip needs to be associated with its parent NAND controller by
+# specifying the following fields: controller number (chip_ctrl) and the chip
+# select line it is connected to (chip_cs). The chip can be connected to only
+# a single (and unique) controller:cs pair.
+#
+[chip]
+# The number of parent controller. This has to fit one of the controller
+# instance number (ctrl_num from [ctrl] section).
+# chip_ctrl=0..3
+chip_ctrl=0
+
+# Chip select line.
+# chip_cs=0..3
+chip_cs=0
+
+# ONFI device identifier.
+# device_id=0x00..0xff
+device_id=0xd3
+
+# ONFI manufacturer identifier.
+# manufacturer_id=0x00..0xff
+manufacturer_id=0xec
+
+# Textual description of the chip.
+# model="model_name"
+model="k9xxg08uxM:1GiB 3,3V 8-bit"
+
+# Textual name of the chip manufacturer.
+# manufacturer="manufacturer name"
+manufacturer="SAMSUNG"
+
+# page_size=[must be power of 2 and >= 512]  (in bytes)
+page_size=2048
+# oob_size=[>0]
+oob_size=64
+# pages_per_block=n*32
+pages_per_block=64
+# blocks_per_lun=[>0]
+blocks_per_lun=4096
+# luns=1..N
+luns=1
+# column_addr_cycle=[1,2]
+column_addr_cycle=2
+# row_addr_cycle=[1,2,3]
+row_addr_cycle=3
+
+# program_time=  (in us)
+program_time=0
+# erase_time=    (in us)
+erase_time=0
+# read_time=     (in us)
+read_time=0
+# ccs_time=      (in us)
+#ccs_time=200
+
+# Simulate write-protect on the chip.
+# write_protect=[yes|no]
+#write_protect=no
+
+# Blocks wear-out threshold. Each block has a counter of program-erase cycles;
+# when this counter reaches 'wear_out' value a given block is treated as a bad
+# block (access will report error).
+#
+# Setting wear_out to 0 means that blocks will never wear out.
+#
+# wear_out=0..100000
+wear_out=50000
+
+# Errors per million read/write bytes. This simulates an accidental read/write
+# block error, which can happen in real devices with certain probability. Note
+# this isn't a bad block condition i.e. the block at which the read/write
+# operation is simulated to fail here remains usable, only the operation has
+# not succeeded (this is where ECC comes into play and is supposed to correct
+# such problems).
+#
+# error_ratio=0..1000000
+#error_ratio=50
+
+# Chip data bus width. All chips connected to the same controller must have
+# the same bus width.
+#
+# width=[8|16]
+width=8
+
+# Bad block map. NANDsim emulates bad block behavior upon accessing a block 
+# with number from the specified list.
+#
+# bad_block_map=[bad_block1, bad_block2-bad_block3, ..bad_blockn]
+bad_block_map=[100-200]
+


Property changes on: trunk/usr.sbin/nandsim/sample.conf
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/Makefile
===================================================================
--- trunk/usr.sbin/nandtool/Makefile	                        (rev 0)
+++ trunk/usr.sbin/nandtool/Makefile	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,12 @@
+# $MidnightBSD$
+# $FreeBSD: stable/10/usr.sbin/nandtool/Makefile 235537 2012-05-17 10:11:18Z gber $
+
+PROG=	nandtool
+SRCS=	nandtool.c nand_read.c nand_write.c nand_erase.c nand_info.c
+SRCS+=	nand_readoob.c nand_writeoob.c
+BINDIR=	/usr/sbin
+DPADD=	${LIBGEOM}
+LDADD=	-lgeom
+MAN=	nandtool.8
+
+.include <bsd.prog.mk>


Property changes on: trunk/usr.sbin/nandtool/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nand_erase.c
===================================================================
--- trunk/usr.sbin/nandtool/nand_erase.c	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nand_erase.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,115 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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: stable/10/usr.sbin/nandtool/nand_erase.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/disk.h>
+#include <libgeom.h>
+#include <dev/nand/nand_dev.h>
+#include "nandtool.h"
+
+int nand_erase(struct cmd_param *params)
+{
+	struct chip_param_io chip_params;
+	char *dev;
+	int fd = -1, ret = 0;
+	off_t pos, count;
+	off_t start, nblocks, i;
+	int block_size, mult;
+
+	if (!(dev = param_get_string(params, "dev"))) {
+		fprintf(stderr, "Please supply valid 'dev' parameter.\n");
+		return (1);
+	}
+
+	if (param_has_value(params, "count"))
+		count = param_get_intx(params, "count");
+	else
+		count = 1;
+
+	if ((fd = g_open(dev, 1)) < 0) {
+		perrorf("Cannot open %s", dev);
+		return (1);
+	}
+
+	if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) {
+		perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
+		ret = 1;
+		goto out;
+	}
+
+	block_size = chip_params.page_size * chip_params.pages_per_block;
+
+	if (param_has_value(params, "page")) {
+		pos = chip_params.page_size * param_get_intx(params, "page");
+		mult = chip_params.page_size;
+	} else if (param_has_value(params, "block")) {
+		pos = block_size * param_get_intx(params, "block");
+		mult = block_size;
+	} else if (param_has_value(params, "pos")) {
+		pos = param_get_intx(params, "pos");
+		mult = 1;
+	} else {
+		/* Erase whole chip */
+		if (ioctl(fd, DIOCGMEDIASIZE, &count) == -1) {
+			ret = 1;
+			goto out;
+		}
+
+		pos = 0;
+		mult = 1;
+	}
+
+	if (pos % block_size) {
+		fprintf(stderr, "Position must be block-size aligned!\n");
+		ret = 1;
+		goto out;
+	}
+
+	count *= mult;
+	start = pos / block_size;
+	nblocks = count / block_size;
+
+	for (i = 0; i < nblocks; i++) {
+		if (g_delete(fd, (start + i) * block_size, block_size) == -1) {
+			perrorf("Cannot erase block %d - probably a bad block",
+			    start + i);
+			ret = 1;
+		}
+	}
+
+out:
+	g_close(fd);
+
+	return (ret);
+}
+


Property changes on: trunk/usr.sbin/nandtool/nand_erase.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nand_info.c
===================================================================
--- trunk/usr.sbin/nandtool/nand_info.c	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nand_info.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,87 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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: stable/10/usr.sbin/nandtool/nand_info.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <libgeom.h>
+#include <sys/disk.h>
+#include <dev/nand/nand_dev.h>
+#include "nandtool.h"
+
+int nand_info(struct cmd_param *params)
+{
+	struct chip_param_io chip_params;
+	int fd = -1, ret = 0;
+	int block_size;
+	off_t chip_size, media_size;
+	const char *dev;
+
+	if ((dev = param_get_string(params, "dev")) == NULL) {
+		fprintf(stderr, "Please supply 'dev' parameter, eg. "
+		    "'dev=/dev/gnand0'\n");
+		return (1);
+	}
+
+	if ((fd = g_open(dev, 1)) == -1) {
+		perrorf("Cannot open %s", dev);
+		return (1);
+	}
+
+	if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) {
+		perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
+		ret = 1;
+		goto out;
+	}
+
+	if (ioctl(fd, DIOCGMEDIASIZE, &media_size) == -1) {
+		perrorf("Cannot ioctl(DIOCGMEDIASIZE)");
+		ret = 1;
+		goto out;
+	}
+
+	block_size = chip_params.page_size * chip_params.pages_per_block;
+	chip_size = block_size * chip_params.blocks;
+
+	printf("Device:\t\t\t%s\n", dev);
+	printf("Page size:\t\t%d bytes\n", chip_params.page_size);
+	printf("Block size:\t\t%d bytes (%d KB)\n", block_size,
+	    block_size / 1024);
+	printf("OOB size per page:\t%d bytes\n", chip_params.oob_size);
+	printf("Chip size:\t\t%jd MB\n", (uintmax_t)(chip_size / 1024 / 1024));
+	printf("Slice size:\t\t%jd MB\n",
+	    (uintmax_t)(media_size / 1024 / 1024));
+
+out:
+	g_close(fd);
+
+	return (ret);
+}


Property changes on: trunk/usr.sbin/nandtool/nand_info.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nand_read.c
===================================================================
--- trunk/usr.sbin/nandtool/nand_read.c	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nand_read.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,140 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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: stable/10/usr.sbin/nandtool/nand_read.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgeom.h>
+#include <sys/disk.h>
+#include <dev/nand/nand_dev.h>
+#include "nandtool.h"
+
+int nand_read(struct cmd_param *params)
+{
+	struct chip_param_io chip_params;
+	int fd = -1, out_fd = -1, done = 0, ret = 0;
+	char *dev, *out;
+	int pos, count, mult, block_size;
+	uint8_t *buf = NULL;
+
+	if (!(dev = param_get_string(params, "dev"))) {
+		fprintf(stderr, "You must specify 'dev' parameter\n");
+		return (1);
+	}
+
+	if ((out = param_get_string(params, "out"))) {
+		out_fd = open(out, O_WRONLY|O_CREAT);
+		if (out_fd == -1) {
+			perrorf("Cannot open %s for writing", out);
+			return (1);
+		}
+	}
+
+	if ((fd = g_open(dev, 1)) == -1) {
+		perrorf("Cannot open %s", dev);
+		ret = 1;
+		goto out;
+	}
+
+	if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) {
+		perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
+		ret = 1;
+		goto out;
+	}
+
+	block_size = chip_params.page_size * chip_params.pages_per_block;
+
+	if (param_has_value(params, "page")) {
+		pos = chip_params.page_size * param_get_int(params, "page");
+		mult = chip_params.page_size;
+	} else if (param_has_value(params, "block")) {
+		pos = block_size * param_get_int(params, "block");
+		mult = block_size;
+	} else if (param_has_value(params, "pos")) {
+		pos = param_get_int(params, "pos");
+		mult = 1;
+		if (pos % chip_params.page_size) {
+			fprintf(stderr, "Position must be page-size aligned!\n");
+			ret = 1;
+			goto out;
+		}
+	} else {
+		fprintf(stderr, "You must specify one of: 'block', 'page',"
+		    "'pos' arguments\n");
+		ret = 1;
+		goto out;
+	}
+
+	if (!(param_has_value(params, "count")))
+		count = mult;
+	else
+		count = param_get_int(params, "count") * mult;
+
+	if (!(buf = malloc(chip_params.page_size))) {
+		perrorf("Cannot allocate buffer [size %x]",
+		    chip_params.page_size);
+		ret = 1;
+		goto out;
+	}
+
+	lseek(fd, pos, SEEK_SET);
+
+	while (done < count) {
+		if ((ret = read(fd, buf, chip_params.page_size)) !=
+		    (int32_t)chip_params.page_size) {
+			perrorf("read error (read %d bytes)", ret);
+			goto out;
+		}
+
+		if (out_fd != -1) {
+			done += ret;
+			if ((ret = write(out_fd, buf, chip_params.page_size)) !=
+			    (int32_t)chip_params.page_size) {
+				perrorf("write error (written %d bytes)", ret);
+				ret = 1;
+				goto out;
+			}
+		} else {
+			hexdumpoffset(buf, chip_params.page_size, done);
+			done += ret;
+		}
+	}
+
+out:
+	g_close(fd);
+	if (out_fd != -1)
+		close(out_fd);
+	if (buf)
+		free(buf);
+
+	return (ret);
+}
+


Property changes on: trunk/usr.sbin/nandtool/nand_read.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nand_readoob.c
===================================================================
--- trunk/usr.sbin/nandtool/nand_readoob.c	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nand_readoob.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,112 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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: stable/10/usr.sbin/nandtool/nand_readoob.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgeom.h>
+#include <sys/types.h>
+#include <sys/disk.h>
+#include <dev/nand/nand_dev.h>
+#include "nandtool.h"
+
+int nand_read_oob(struct cmd_param *params)
+{
+	struct chip_param_io chip_params;
+	struct nand_oob_rw req;
+	char *dev, *out;
+	int fd = -1, fd_out = -1, ret = 0;
+	int page;
+	uint8_t *buf = NULL;
+
+	if ((page = param_get_int(params, "page")) < 0) {
+		fprintf(stderr, "You must supply valid 'page' argument.\n");
+		return (1);
+	}
+
+	if (!(dev = param_get_string(params, "dev"))) {
+		fprintf(stderr, "You must supply 'dev' argument.\n");
+		return (1);
+	}
+
+	if ((out = param_get_string(params, "out"))) {
+		if ((fd_out = open(out, O_WRONLY | O_CREAT)) == -1) {
+			perrorf("Cannot open %s", out);
+			ret = 1;
+			goto out;
+		}
+	}
+
+	if ((fd = g_open(dev, 1)) == -1) {
+		perrorf("Cannot open %s", dev);
+		ret = 1;
+		goto out;
+	}
+
+	if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) {
+		perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
+		ret = 1;
+		goto out;
+	}
+
+	buf = malloc(chip_params.oob_size);
+	if (buf == NULL) {
+		perrorf("Cannot allocate %d bytes\n", chip_params.oob_size);
+		ret = 1;
+		goto out;
+	}
+
+	req.page = page;
+	req.len = chip_params.oob_size;
+	req.data = buf;
+
+	if (ioctl(fd, NAND_IO_OOB_READ, &req) == -1) {
+		perrorf("Cannot read OOB from %s", dev);
+		ret = 1;
+		goto out;
+	}
+
+	if (fd_out != -1)
+		write(fd_out, buf, chip_params.oob_size);
+	else
+		hexdump(buf, chip_params.oob_size);
+
+out:
+	close(fd_out);
+
+	if (fd != -1)
+		g_close(fd);
+	if (buf)
+		free(buf);
+
+	return (ret);
+}
+


Property changes on: trunk/usr.sbin/nandtool/nand_readoob.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nand_write.c
===================================================================
--- trunk/usr.sbin/nandtool/nand_write.c	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nand_write.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,144 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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: stable/10/usr.sbin/nandtool/nand_write.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgeom.h>
+#include <sys/disk.h>
+#include <dev/nand/nand_dev.h>
+#include "nandtool.h"
+
+int nand_write(struct cmd_param *params)
+{
+	struct chip_param_io chip_params;
+	char *dev, *file;
+	int in_fd = -1, ret = 0, done = 0;
+	int fd, block_size, mult, pos, count;
+	uint8_t *buf = NULL;
+
+	if (!(dev = param_get_string(params, "dev"))) {
+		fprintf(stderr, "Please supply 'dev' argument.\n");
+		return (1);
+	}
+
+	if (!(file = param_get_string(params, "in"))) {
+		fprintf(stderr, "Please supply 'in' argument.\n");
+		return (1);
+	}
+
+	if ((fd = g_open(dev, 1)) == -1) {
+		perrorf("Cannot open %s", dev);
+		return (1);
+	}
+
+	if ((in_fd = open(file, O_RDONLY)) == -1) {
+		perrorf("Cannot open file %s", file);
+		ret = 1;
+		goto out;
+	}
+
+	if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) {
+		perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
+		ret = 1;
+		goto out;
+	}
+
+	block_size = chip_params.page_size * chip_params.pages_per_block;
+
+	if (param_has_value(params, "page")) {
+		pos = chip_params.page_size * param_get_int(params, "page");
+		mult = chip_params.page_size;
+	} else if (param_has_value(params, "block")) {
+		pos = block_size * param_get_int(params, "block");
+		mult = block_size;
+	} else if (param_has_value(params, "pos")) {
+		pos = param_get_int(params, "pos");
+		mult = 1;
+		if (pos % chip_params.page_size) {
+			fprintf(stderr, "Position must be page-size "
+			    "aligned!\n");
+			ret = 1;
+			goto out;
+		}
+	} else {
+		fprintf(stderr, "You must specify one of: 'block', 'page',"
+		    "'pos' arguments\n");
+		ret = 1;
+		goto out;
+	}
+
+	if (!(param_has_value(params, "count")))
+		count = mult;
+	else
+		count = param_get_int(params, "count") * mult;
+
+	if (!(buf = malloc(chip_params.page_size))) {
+		perrorf("Cannot allocate buffer [size %x]",
+		    chip_params.page_size);
+		ret = 1;
+		goto out;
+	}
+
+	lseek(fd, pos, SEEK_SET);
+
+	while (done < count) {
+		if ((ret = read(in_fd, buf, chip_params.page_size)) !=
+		    (int32_t)chip_params.page_size) {
+			if (ret > 0) {
+				/* End of file ahead, truncate here */
+				break;
+			} else {
+				perrorf("Cannot read from %s", file);
+				ret = 1;
+				goto out;
+			}
+		}
+
+		if ((ret = write(fd, buf, chip_params.page_size)) !=
+		    (int32_t)chip_params.page_size) {
+			ret = 1;
+			goto out;
+		}
+
+		done += ret;
+	}
+
+out:
+	g_close(fd);
+	if (in_fd != -1)
+		close(in_fd);
+	if (buf)
+		free(buf);
+
+	return (ret);
+}
+


Property changes on: trunk/usr.sbin/nandtool/nand_write.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nand_writeoob.c
===================================================================
--- trunk/usr.sbin/nandtool/nand_writeoob.c	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nand_writeoob.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,114 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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: stable/10/usr.sbin/nandtool/nand_writeoob.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgeom.h>
+#include <sys/disk.h>
+#include <dev/nand/nand_dev.h>
+#include "nandtool.h"
+
+int nand_write_oob(struct cmd_param *params)
+{
+	struct chip_param_io chip_params;
+	struct nand_oob_rw req;
+	char *dev, *in;
+	int fd = -1, fd_in = -1, ret = 0;
+	uint8_t *buf = NULL;
+	int page;
+
+	if (!(dev = param_get_string(params, "dev"))) {
+		fprintf(stderr, "Please supply valid 'dev' parameter.\n");
+		return (1);
+	}
+
+	if (!(in = param_get_string(params, "in"))) {
+		fprintf(stderr, "Please supply valid 'in' parameter.\n");
+		return (1);
+	}
+
+	if ((page = param_get_int(params, "page")) < 0) {
+		fprintf(stderr, "Please supply valid 'page' parameter.\n");
+		return (1);
+	}
+
+	if ((fd = g_open(dev, 1)) == -1) {
+		perrorf("Cannot open %s", dev);
+		return (1);
+	}
+
+	if ((fd_in = open(in, O_RDONLY)) == -1) {
+		perrorf("Cannot open %s", in);
+		ret = 1;
+		goto out;
+	}
+
+	if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) {
+		perrorf("Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
+		ret = 1;
+		goto out;
+	}
+
+	buf = malloc(chip_params.oob_size);
+	if (buf == NULL) {
+		perrorf("Cannot allocate %d bytes\n", chip_params.oob_size);
+		ret = 1;
+		goto out;
+	}
+
+	if (read(fd_in, buf, chip_params.oob_size) == -1) {
+		perrorf("Cannot read from %s", in);
+		ret = 1;
+		goto out;
+	}
+
+	req.page = page;
+	req.len = chip_params.oob_size;
+	req.data = buf;
+
+	if (ioctl(fd, NAND_IO_OOB_PROG, &req) == -1) {
+		perrorf("Cannot write OOB to %s", dev);
+		ret = 1;
+		goto out;
+	}
+
+out:
+	g_close(fd);
+	if (fd_in != -1)
+		close(fd_in);
+	if (buf)
+		free(buf);
+
+	return (ret);
+}
+
+


Property changes on: trunk/usr.sbin/nandtool/nand_writeoob.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nandtool.8
===================================================================
--- trunk/usr.sbin/nandtool/nandtool.8	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nandtool.8	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,185 @@
+.\" $MidnightBSD$
+.\" Copyright (c) 2010 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.
+.\"
+.\" $FreeBSD: stable/10/usr.sbin/nandtool/nandtool.8 235544 2012-05-17 11:50:12Z joel $
+.\"
+.Dd April 10, 2012
+.Dt NANDTOOL 8
+.Os
+.Sh NAME
+.Nm nandtool
+.Nd NAND devices swiss army knife
+.Sh SYNOPSIS
+.Nm
+.Ar command
+.Op Ar operands ...
+.Sh DESCRIPTION
+The
+.Nm
+utility can be used to perform various operations on
+.Xr gnand 4
+devices (read, write, erase,
+read and write OOB area and to get info about NAND flash chip).
+.Pp
+The following commands are available:
+.Bl -tag -width ".Cm of Ns = Ns Ar file"
+.It Cm read Ns
+Read pages from NAND device.
+.It Cm write Ns
+Write pages to NAND device.
+.It Cm erase Ns
+Erase blocks.
+Requires offset aligned to block granularity.
+.It Cm info Ns
+Get information about NAND chip (page size, block size, OOB area size, chip size
+and media size)
+.It Cm readoob Ns
+Read OOB area from specified page.
+.It Cm writeoob Ns
+Write OOB area bound to specified page.
+.It Cm help Ns
+Get usage info.
+.El
+.Sh COMMAND read
+The following operands are available for
+.Nm
+.Cm read
+command:
+.Bl -tag -width ".Cm of Ns = Ns Ar file"
+.It Cm dev Ns = Ns Ar <path>
+Path to a
+.Xr gnand 4
+device node, required for all operations.
+.It Cm out Ns = Ns Ar <file>
+Output file path. If not specified, page contents
+will be dumped to stdout in format similar to
+.Xr hexdump 1
+.It Cm page Ns = Ns Ar <n>
+Offset on device, expressed as page number.
+.It Cm block Ns = Ns Ar <n>
+Offset on device, expressed as block number.
+.It Cm pos Ns = Ns Ar <n>
+Offset on device, expressed in bytes (however, must be aligned
+to page granularity).
+.It Cm count Ns = Ns Ar <n>
+Count of objects (pages, blocks, bytes).
+.El
+.Sh COMMAND readoob
+The following operands are available for
+.Nm
+.Cm readoob
+command:
+.Bl -tag -width ".Cm of Ns = Ns Ar file"
+.It Cm dev Ns = Ns Ar <path>
+Path to NAND device node.
+.It Cm page Ns = Ns Ar <n>
+Offset on device, expressed as page number.
+.It Cm out Ns = Ns Ar <file>
+Output file path, optional.
+.El
+.Sh COMMAND write
+The following operands are available for
+.Nm
+.Cm write
+command:
+.Bl -tag -width ".Cm of Ns = Ns Ar file"
+.It Cm dev Ns = Ns Ar <path>
+Path to NAND device node.
+.It Cm page Ns = Ns Ar <n>
+Offset on device, expressed as page number.
+.It Cm block Ns = Ns Ar <n>
+Offset on device, expressed as block number.
+.It Cm pos Ns = Ns Ar <n>
+Offset on device, expressed in bytes (however, must be aligned
+to page granularity).
+.It Cm in Ns = Ns Ar <file>
+Input file path.
+.El
+.Sh COMMAND writeoob
+The following operands are available for
+.Nm
+.Cm writeoob
+command:
+.Bl -tag -width ".Cm of Ns = Ns Ar file"
+.It Cm dev Ns = Ns Ar <path>
+Path to NAND device node.
+.It Cm page Ns = Ns Ar <n>
+Offset on device, expressed as page number.
+.It Cm in Ns = Ns Ar <file>
+Input file path.
+.El
+.Sh COMMAND erase
+The following operands are available for
+.Nm
+.Cm erase
+command:
+.Bl -tag -width ".Cm of Ns = Ns Ar file"
+.It Cm dev Ns = Ns Ar <path>
+Path to NAND device node.
+.It Cm page Ns = Ns Ar <n>
+Offset on device, expressed as page number.
+.It Cm block Ns = Ns Ar <n>
+Offset on device, expressed as block number.
+.It Cm pos Ns = Ns Ar <n>
+Offset on device, epressed in bytes (however, must be aligned
+to block granularity).
+.It Cm count Ns = Ns Ar <n>
+Count of objects (pages, blocks, bytes).
+.El
+.Pp
+WARNING: The only required parameter for the \fBerase\fP command is
+.Ar dev .
+When no other arguments are provided the whole device is erased!
+.Sh COMMAND info
+There is only one operand available for
+.Nm
+.Cm info
+command:
+.Bl -tag -width ".Cm of Ns = Ns Ar file"
+.It Cm dev Ns = Ns Ar <path>
+Path to NAND device node.
+.El
+.Sh COMMAND help
+There is only one operand available for
+.Nm
+.Cm help
+command:
+.Bl -tag -width ".Cm of Ns = Ns Ar file"
+.It Cm topic Ns = Ns Ar <name>
+Help topic.
+.El
+.Sh EXIT STATUS
+.Ex -std
+If the supplied argument
+.Ar dev
+points to a device node other than gnand<num> or gnand.raw<num> both
+.Nm
+.Cm readoob
+and
+.Nm
+.Cm writeoob
+return error.
+.Sh SEE ALSO
+.Xr gnand 4


Property changes on: trunk/usr.sbin/nandtool/nandtool.8
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nandtool.c
===================================================================
--- trunk/usr.sbin/nandtool/nandtool.c	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nandtool.c	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,284 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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: stable/10/usr.sbin/nandtool/nandtool.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <sysexits.h>
+#include <libgeom.h>
+#include "nandtool.h"
+#include "usage.h"
+
+int usage(struct cmd_param *);
+
+static const struct {
+	const char	*name;
+	const char	*usage;
+	int		(*handler)(struct cmd_param *);
+} commands[] = {
+	{ "help", nand_help_usage, usage },
+	{ "read", nand_read_usage, nand_read },
+	{ "write", nand_write_usage, nand_write },
+	{ "erase", nand_erase_usage, nand_erase },
+	{ "readoob", nand_read_oob_usage, nand_read_oob },
+	{ "writeoob", nand_write_oob_usage, nand_write_oob },
+	{ "info", nand_info_usage, nand_info },
+	{ NULL, NULL, NULL },
+};
+
+static char *
+_param_get_stringx(struct cmd_param *params, const char *name, int doexit)
+{
+	int i;
+
+	for (i = 0; params[i].name[0] != '\0'; i++) {
+		if (!strcmp(params[i].name, name))
+			return params[i].value;
+	}
+
+	if (doexit) {
+		perrorf("Missing parameter %s", name);
+		exit(1);
+	}
+	return (NULL);
+}
+
+char *
+param_get_string(struct cmd_param *params, const char *name)
+{
+
+	return (_param_get_stringx(params, name, 0));
+}
+
+static int
+_param_get_intx(struct cmd_param *params, const char *name, int doexit)
+{
+	int ret;
+	char *str = _param_get_stringx(params, name, doexit);
+
+	if (!str)
+		return (-1);
+
+	errno = 0;
+	ret = (int)strtol(str, (char **)NULL, 10);
+	if (errno) {
+		if (doexit) {
+			perrorf("Invalid value for parameter %s", name);
+			exit(1);
+		}
+		return (-1);
+	}
+
+	return (ret);
+}
+
+int
+param_get_intx(struct cmd_param *params, const char *name)
+{
+
+	return (_param_get_intx(params, name, 1));
+}
+
+int
+param_get_int(struct cmd_param *params, const char *name)
+{
+
+	return (_param_get_intx(params, name, 0));
+}
+
+int
+param_get_boolean(struct cmd_param *params, const char *name)
+{
+	char *str = param_get_string(params, name);
+
+	if (!str)
+		return (0);
+
+	if (!strcmp(str, "true") || !strcmp(str, "yes"))
+		return (1);
+
+	return (0);
+}
+
+int
+param_has_value(struct cmd_param *params, const char *name)
+{
+	int i;
+
+	for (i = 0; params[i].name[0] != '\0'; i++) {
+		if (!strcmp(params[i].name, name))
+			return (1);
+	}
+
+	return (0);
+}
+
+int
+param_get_count(struct cmd_param *params)
+{
+	int i;
+
+	for (i = 0; params[i].name[0] != '\0'; i++);
+
+	return (i);
+}
+
+void
+hexdumpoffset(uint8_t *buf, int length, int off)
+{
+	int i, j;
+	for (i = 0; i < length; i += 16) {
+		printf("%08x: ", off + i);
+
+		for (j = 0; j < 16; j++)
+			printf("%02x ", buf[i+j]);
+
+		printf("| ");
+
+		for (j = 0; j < 16; j++) {
+			printf("%c", isalnum(buf[i+j])
+			    ? buf[i+j]
+			    : '.');
+		}
+
+		printf("\n");
+	}
+}
+
+void
+hexdump(uint8_t *buf, int length)
+{
+
+	hexdumpoffset(buf, length, 0);
+}
+
+void *
+xmalloc(size_t len)
+{
+	void *ret = malloc(len);
+
+	if (!ret) {
+		fprintf(stderr, "Cannot allocate buffer of %zd bytes. "
+		    "Exiting.\n", len);
+		exit(EX_OSERR);
+	}
+
+	return (ret);
+}
+
+void
+perrorf(const char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	vfprintf(stderr, format, args);
+	va_end(args);
+	fprintf(stderr, ": %s\n", strerror(errno));
+}
+
+int
+usage(struct cmd_param *params)
+{
+	int i;
+
+	if (!params || !param_get_count(params)) {
+		fprintf(stderr, "Usage: nandtool <command> [arguments...]\n");
+		fprintf(stderr, "Arguments are in form 'name=value'.\n\n");
+		fprintf(stderr, "Available commands:\n");
+
+		for (i = 0; commands[i].name != NULL; i++)
+			fprintf(stderr, "\t%s\n", commands[i].name);
+
+		fprintf(stderr, "\n");
+		fprintf(stderr, "For information about particular command, "
+		    "type:\n");
+		fprintf(stderr, "'nandtool help topic=<command>'\n");
+	} else if (param_has_value(params, "topic")) {
+		for (i = 0; commands[i].name != NULL; i++) {
+			if (!strcmp(param_get_string(params, "topic"),
+			    commands[i].name)) {
+				fprintf(stderr, commands[i].usage, "nandtool");
+				return (0);
+			}
+		}
+
+		fprintf(stderr, "No such command\n");
+		return (EX_SOFTWARE);
+	} else {
+		fprintf(stderr, "Wrong arguments given. Try: 'nandtool help'\n");
+	}
+
+	return (EX_USAGE);
+}
+
+int
+main(int argc, const char *argv[])
+{
+	struct cmd_param *params;
+	int i, ret, idx;
+
+	if (argc < 2) {
+		usage(NULL);
+		return (0);
+	}
+
+	params = malloc(sizeof(struct cmd_param) * (argc - 1));
+
+	for (i = 2, idx = 0; i < argc; i++, idx++) {
+		if (sscanf(argv[i], "%63[^=]=%63s", params[idx].name,
+		    params[idx].value) < 2) {
+			fprintf(stderr, "Syntax error in argument %d. "
+			    "Argument should be in form 'name=value'.\n", i);
+			free(params);
+			return (-1);
+		}
+	}
+
+	params[idx].name[0] = '\0';
+	params[idx].value[0] = '\0';
+
+	for (i = 0; commands[i].name != NULL; i++) {
+		if (!strcmp(commands[i].name, argv[1])) {
+			ret = commands[i].handler(params);
+			free(params);
+			return (ret);
+		}
+	}
+
+	free(params);
+	fprintf(stderr, "Unknown command. Try '%s help'\n", argv[0]);
+
+	return (-1);
+}
+


Property changes on: trunk/usr.sbin/nandtool/nandtool.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/nandtool.h
===================================================================
--- trunk/usr.sbin/nandtool/nandtool.h	                        (rev 0)
+++ trunk/usr.sbin/nandtool/nandtool.h	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,58 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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.
+ *
+ * $FreeBSD: stable/10/usr.sbin/nandtool/nandtool.h 235537 2012-05-17 10:11:18Z gber $
+ */
+
+#ifndef	__UTILS_H
+#define	__UTILS_H
+
+struct cmd_param
+{
+	char	name[64];
+	char	value[64];
+};
+
+char *param_get_string(struct cmd_param *, const char *);
+int param_get_int(struct cmd_param *, const char *);
+int param_get_intx(struct cmd_param *, const char *);
+int param_get_boolean(struct cmd_param *, const char *);
+int param_has_value(struct cmd_param *, const char *);
+int param_get_count(struct cmd_param *);
+void perrorf(const char *, ...);
+void hexdumpoffset(uint8_t *, int, int);
+void hexdump(uint8_t *, int);
+void *xmalloc(size_t);
+
+/* Command handlers */
+int nand_read(struct cmd_param *);
+int nand_write(struct cmd_param *);
+int nand_read_oob(struct cmd_param *);
+int nand_write_oob(struct cmd_param *);
+int nand_erase(struct cmd_param *);
+int nand_info(struct cmd_param *);
+
+#endif	/* __UTILS_H */


Property changes on: trunk/usr.sbin/nandtool/nandtool.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/nandtool/usage.h
===================================================================
--- trunk/usr.sbin/nandtool/usage.h	                        (rev 0)
+++ trunk/usr.sbin/nandtool/usage.h	2018-06-03 23:25:31 UTC (rev 10379)
@@ -0,0 +1,113 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010-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.
+ *
+ * $FreeBSD: stable/10/usr.sbin/nandtool/usage.h 235537 2012-05-17 10:11:18Z gber $
+ */
+
+#ifndef	__USAGE_H
+#define	__USAGE_H
+
+static const char nand_help_usage[] =
+	"Usage: %s help topic=<cmd>\n"
+	"\n"
+	"Arguments:\n"
+	"\tcmd\t- [help|read|write|erase|readoob|writeoob|info]\n"
+	"\n";
+
+static const char nand_read_usage[] =
+	"Usage: %s read dev=<gnand_device> (block|page|pos)=n [count=n]\n"
+	"\n"
+	"Arguments:\n"
+	"\tdev\t- path to gnand device node\n"
+	"\tblock\t- starting block or\n"
+	"\tpage\t- starting page or\n"
+	"\tpos\t- starting position (in bytes, must be page-aligned)\n"
+	"\tout\t- output file (hexdump to stdout if not supplied)\n"
+	"\n"
+	"Note that you can only specify only one of: 'block', 'page', 'pos'\n"
+	"parameters at once. 'count' parameter is meaningful in terms of used\n"
+	"unit (page, block or byte).\n";
+
+static const char nand_write_usage[] =
+	"Usage: %s write dev=<gnand_device> in=<file> (block|page|pos)=n [count=n]\n"
+	"\n"
+	"Arguments:\n"
+	"\tdev\t- path to gnand device node\n"
+	"\tin\t- path to input file which be writed to gnand\n"
+	"\tblock\t- starting block or\n"
+	"\tpage\t- starting page or\n"
+	"\tpos\t- starting position (in bytes, must be page-aligned)\n"
+	"\tcount\t- byte/page/block count\n"
+	"\n"
+	"";
+
+static const char nand_erase_usage[] =
+	"Usage: %s erase dev=<gnand_device> (block|page|pos)=n [count=n]\n"
+	"\n"
+	"Arguments:\n"
+	"\tdev\t- path to gnand device node\n"
+	"\tblock\t- starting block or\n"
+	"\tpage\t- starting page or\n"
+	"\tpos\t- starting position (in bytes, muse be block-aligned)\n"
+	"\tcount\t- byte/page/block count\n"
+	"\n"
+	"NOTE: position and count for erase operation MUST be block-aligned\n";
+
+static const char nand_read_oob_usage[] =
+	"Usage: %s readoob dev=<gnand_device> page=n [out=file] [count=n]\n"
+	"\n"
+	"Arguments:\n"
+	"\tdev\t- path to gnand device node\n"
+	"\tpage\t- page (page) number\n"
+	"\tout\t- outut file (hexdump to stdout if not supplied)\n"
+	"\tcount\t- page count (default is 1)\n"
+	"\n"
+	"If you supply count parameter with value other than 1, data will be\n"
+	"read from subsequent page's OOB areas\n";
+
+static const char nand_write_oob_usage[] =
+	"Usage: %s writeoob dev=<gnand_device> in=<file> page=n [count=n]\n"
+	"\n"
+	"\tdev\t- path to gnand device node\n"
+	"\tin\t- path to file containing data which will be written\n"
+	"\tpage\t- page (page) number\n"
+	"\n"
+	"If you supply count parameter with value other than 1, data will be\n"
+	"written to subsequent page's OOB areas\n";
+
+static const char nand_info_usage[] =
+	"Usage: %s info dev=<gnand_device>\n"
+	"\n"
+	"Arguments:\n"
+	"\tdev\t- path to gnand device node\n";
+
+static const char nand_stats_usage[] =
+	"Usage: %s stats dev=<gnand_device> (page|block)=<n>\n"
+	"\n"
+	"Arguments:\n"
+	"\tdev\t- path to gnand device node\n";
+
+#endif	/* __USAGE_H */


Property changes on: trunk/usr.sbin/nandtool/usage.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list