summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nandsim/nandsim_cfgparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/nandsim/nandsim_cfgparse.c')
-rw-r--r--usr.sbin/nandsim/nandsim_cfgparse.c957
1 files changed, 957 insertions, 0 deletions
diff --git a/usr.sbin/nandsim/nandsim_cfgparse.c b/usr.sbin/nandsim/nandsim_cfgparse.c
new file mode 100644
index 0000000..40e8d4c
--- /dev/null
+++ b/usr.sbin/nandsim/nandsim_cfgparse.c
@@ -0,0 +1,957 @@
+/*-
+ * 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.
+ */
+__FBSDID("$FreeBSD$");
+
+#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},
+};
+
+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 overriden.
+ */
+ 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 overriden.
+ */
+ 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 neccesary 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 *)&sections;
+ 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 *)&sections;
+ 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);
+}
OpenPOWER on IntegriCloud