diff options
author | gber <gber@FreeBSD.org> | 2012-05-17 10:11:18 +0000 |
---|---|---|
committer | gber <gber@FreeBSD.org> | 2012-05-17 10:11:18 +0000 |
commit | 6f7c7353004e2ff9709b326a4008ce8ea63d9270 (patch) | |
tree | a325137a898341311de8641f7212e28b7d87950e /usr.sbin/nandsim/nandsim_cfgparse.c | |
parent | 661b9d94414ea6d11d5b7960aef1f172975ce52b (diff) | |
download | FreeBSD-src-6f7c7353004e2ff9709b326a4008ce8ea63d9270.zip FreeBSD-src-6f7c7353004e2ff9709b326a4008ce8ea63d9270.tar.gz |
Import work done under project/nand (@235533) into head.
The NAND Flash environment consists of several distinct components:
- NAND framework (drivers harness for NAND controllers and NAND chips)
- NAND simulator (NANDsim)
- NAND file system (NAND FS)
- Companion tools and utilities
- Documentation (manual pages)
This work is still experimental. Please use with caution.
Obtained from: Semihalf
Supported by: FreeBSD Foundation, Juniper Networks
Diffstat (limited to 'usr.sbin/nandsim/nandsim_cfgparse.c')
-rw-r--r-- | usr.sbin/nandsim/nandsim_cfgparse.c | 957 |
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 *)§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); +} |