2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2009-2012 Semihalf
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/errno.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
36 #include <dev/nand/nandsim.h>
46 #include "nandsim_cfgparse.h"
48 #define warn(fmt, args...) do { \
49 printf("WARNING: " fmt "\n", ##args); } while (0)
51 #define error(fmt, args...) do { \
52 printf("ERROR: " fmt "\n", ##args); } while (0)
54 #define MSG_MANDATORYKEYMISSING "mandatory key \"%s\" value belonging to " \
55 "section \"%s\" is missing!\n"
61 #define debug(fmt, args...) do { \
62 printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0)
64 #define debug(fmt, args...) do {} while(0)
67 #define STRBUFSIZ 2000
69 /* Macros extracts type and type size */
70 #define TYPE(x) ((x) & 0xf8)
71 #define SIZE(x) (((x) & 0x07))
73 /* Erase/Prog/Read time max and min values */
74 #define DELAYTIME_MIN 10000
75 #define DELAYTIME_MAX 10000000
77 /* Structure holding configuration for controller. */
78 static struct sim_ctrl ctrl_conf;
79 /* Structure holding configuration for chip. */
80 static struct sim_chip chip_conf;
82 static struct nandsim_key nandsim_ctrl_keys[] = {
83 {"num_cs", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num_cs, 0},
84 {"ctrl_num", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num, 0},
86 {"ecc_layout", 1, VALUE_UINTARRAY | SIZE_16,
87 (void *)&ctrl_conf.ecc_layout, MAX_ECC_BYTES},
89 {"filename", 0, VALUE_STRING,
90 (void *)&ctrl_conf.filename, FILENAME_SIZE},
92 {"ecc", 0, VALUE_BOOL, (void *)&ctrl_conf.ecc, 0},
93 {NULL, 0, 0, NULL, 0},
96 static struct nandsim_key nandsim_chip_keys[] = {
97 {"chip_cs", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.num, 0},
98 {"chip_ctrl", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.ctrl_num,
100 {"device_id", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.device_id,
102 {"manufacturer_id", 1, VALUE_UINT | SIZE_8,
103 (void *)&chip_conf.manufact_id, 0},
104 {"model", 0, VALUE_STRING, (void *)&chip_conf.device_model,
106 {"manufacturer", 0, VALUE_STRING, (void *)&chip_conf.manufacturer,
108 {"page_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.page_size,
110 {"oob_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.oob_size,
112 {"pages_per_block", 1, VALUE_UINT | SIZE_32,
113 (void *)&chip_conf.pgs_per_blk, 0},
114 {"blocks_per_lun", 1, VALUE_UINT | SIZE_32,
115 (void *)&chip_conf.blks_per_lun, 0},
116 {"luns", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.luns, 0},
117 {"column_addr_cycle", 1,VALUE_UINT | SIZE_8,
118 (void *)&chip_conf.col_addr_cycles, 0},
119 {"row_addr_cycle", 1, VALUE_UINT | SIZE_8,
120 (void *)&chip_conf.row_addr_cycles, 0},
121 {"program_time", 0, VALUE_UINT | SIZE_32,
122 (void *)&chip_conf.prog_time, 0},
123 {"erase_time", 0, VALUE_UINT | SIZE_32,
124 (void *)&chip_conf.erase_time, 0},
125 {"read_time", 0, VALUE_UINT | SIZE_32,
126 (void *)&chip_conf.read_time, 0},
127 {"width", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.width, 0},
128 {"wear_out", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.wear_level,
130 {"bad_block_map", 0, VALUE_UINTARRAY | SIZE_32,
131 (void *)&chip_conf.bad_block_map, MAX_BAD_BLOCKS},
132 {NULL, 0, 0, NULL, 0},
135 static struct nandsim_section sections[] = {
136 {"ctrl", (struct nandsim_key *)&nandsim_ctrl_keys},
137 {"chip", (struct nandsim_key *)&nandsim_chip_keys},
141 static uint8_t logoutputtoint(char *, int *);
142 static uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int);
143 static uint8_t validate_ctrls(struct sim_ctrl *, int);
144 static int configure_sim(const char *, struct rcfile *);
145 static int create_ctrls(struct rcfile *, struct sim_ctrl **, int *);
146 static int create_chips(struct rcfile *, struct sim_chip **, int *);
147 static void destroy_ctrls(struct sim_ctrl *);
148 static void destroy_chips(struct sim_chip *);
149 static int validate_section_config(struct rcfile *, const char *, int);
152 convert_argint(char *arg, int *value)
155 if (arg == NULL || value == NULL)
159 *value = (int)strtol(arg, NULL, 0);
160 if (*value == 0 && errno != 0) {
161 error("Cannot convert to number argument \'%s\'", arg);
168 convert_arguint(char *arg, unsigned int *value)
171 if (arg == NULL || value == NULL)
175 *value = (unsigned int)strtol(arg, NULL, 0);
176 if (*value == 0 && errno != 0) {
177 error("Cannot convert to number argument \'%s\'", arg);
183 /* Parse given ',' separated list of bytes into buffer. */
185 parse_intarray(char *array, int **buffer)
187 char *tmp, *tmpstr, *origstr;
188 unsigned int currbufp = 0, i;
189 unsigned int count = 0, from = 0, to = 0;
191 /* Remove square braces */
194 if (array[strlen(array)-1] == ']')
195 array[strlen(array)-1] = ',';
197 from = strlen(array);
198 origstr = (char *)malloc(sizeof(char) * from);
199 strcpy(origstr, array);
201 tmpstr = (char *)strtok(array, ",");
202 /* First loop checks for how big int array we need to allocate */
203 while (tmpstr != NULL) {
205 if ((tmp = strchr(tmpstr, '-')) != NULL) {
207 if (convert_arguint(tmpstr, &from) ||
208 convert_arguint(tmp, &to)) {
213 count += to - from + 1;
215 if (convert_arguint(tmpstr, &from)) {
221 tmpstr = (char *)strtok(NULL, ",");
227 /* Allocate buffer of ints */
228 tmpstr = (char *)strtok(origstr, ",");
229 *buffer = malloc(count * sizeof(int));
231 /* Second loop is just inserting converted values into int array */
232 while (tmpstr != NULL) {
234 if ((tmp = strchr(tmpstr, '-')) != NULL) {
236 from = strtol(tmpstr, NULL, 0);
237 to = strtol(tmp, NULL, 0);
238 tmpstr = strtok(NULL, ",");
239 for (i = from; i <= to; i ++)
240 (*buffer)[currbufp++] = i;
244 from = (int)strtol(tmpstr, NULL, 0);
245 (*buffer)[currbufp++] = from;
246 tmpstr = (char *)strtok(NULL, ",");
253 /* Convert logoutput strings literals into appropriate ints. */
255 logoutputtoint(char *logoutput, int *output)
259 if (strcmp(logoutput, "file") == 0)
260 out = NANDSIM_OUTPUT_FILE;
262 else if (strcmp(logoutput, "console") == 0)
263 out = NANDSIM_OUTPUT_CONSOLE;
265 else if (strcmp(logoutput, "ram") == 0)
266 out = NANDSIM_OUTPUT_RAM;
268 else if (strcmp(logoutput, "none") == 0)
269 out = NANDSIM_OUTPUT_NONE;
282 configure_sim(const char *devfname, struct rcfile *f)
284 struct sim_param sim_conf;
288 err = rc_getint(f, "sim", 0, "log_level", &tmpv);
290 if (tmpv < 0 || tmpv > 255 || err) {
291 error("Bad log level specified (%d)\n", tmpv);
294 sim_conf.log_level = tmpv;
296 rc_getstring(f, "sim", 0, "log_output", 255, (char *)&buf);
299 err = logoutputtoint((char *)&buf, &tmpv);
301 error("Log output specified in config file does not seem to "
302 "be valid (%s)!", (char *)&buf);
306 sim_conf.log_output = tmpv;
308 fd = open(devfname, O_RDWR);
310 error("could not open simulator device file (%s)!",
315 err = ioctl(fd, NANDSIM_SIM_PARAM, &sim_conf);
317 error("simulator parameters could not be modified: %s",
328 create_ctrls(struct rcfile *f, struct sim_ctrl **ctrls, int *cnt)
331 struct sim_ctrl *ctrlsptr;
333 count = rc_getsectionscount(f, "ctrl");
334 if (count > MAX_SIM_DEV) {
335 error("Too many CTRL sections specified(%d)", count);
337 } else if (count == 0) {
338 error("No ctrl sections specified");
342 ctrlsptr = (struct sim_ctrl *)malloc(sizeof(struct sim_ctrl) * count);
343 if (ctrlsptr == NULL) {
344 error("Could not allocate memory for ctrl configuration");
348 for (i = 0; i < count; i++) {
349 bzero((void *)&ctrl_conf, sizeof(ctrl_conf));
352 * ECC layout have to end up with 0xffff, so
353 * we're filling buffer with 0xff. If ecc_layout is
354 * defined in config file, values will be overridden.
356 memset((void *)&ctrl_conf.ecc_layout, 0xff,
357 sizeof(ctrl_conf.ecc_layout));
359 if (validate_section_config(f, "ctrl", i) != 0) {
364 if (parse_section(f, "ctrl", i) != 0) {
369 memcpy(&ctrlsptr[i], &ctrl_conf, sizeof(ctrl_conf));
370 /* Try to create ctrl with config parsed */
371 debug("NUM=%d\nNUM_CS=%d\nECC=%d\nFILENAME=%s\nECC_LAYOUT[0]"
372 "=%d\nECC_LAYOUT[1]=%d\n\n",
373 ctrlsptr[i].num, ctrlsptr[i].num_cs, ctrlsptr[i].ecc,
374 ctrlsptr[i].filename, ctrlsptr[i].ecc_layout[0],
375 ctrlsptr[i].ecc_layout[1]);
383 destroy_ctrls(struct sim_ctrl *ctrls)
390 create_chips(struct rcfile *f, struct sim_chip **chips, int *cnt)
392 struct sim_chip *chipsptr;
395 count = rc_getsectionscount(f, "chip");
396 if (count > (MAX_CTRL_CS * MAX_SIM_DEV)) {
397 error("Too many chip sections specified(%d)", count);
399 } else if (count == 0) {
400 error("No chip sections specified");
404 chipsptr = (struct sim_chip *)malloc(sizeof(struct sim_chip) * count);
405 if (chipsptr == NULL) {
406 error("Could not allocate memory for chip configuration");
410 for (i = 0; i < count; i++) {
411 bzero((void *)&chip_conf, sizeof(chip_conf));
414 * Bad block map have to end up with 0xffff, so
415 * we're filling array with 0xff. If bad block map is
416 * defined in config file, values will be overridden.
418 memset((void *)&chip_conf.bad_block_map, 0xff,
419 sizeof(chip_conf.bad_block_map));
421 if (validate_section_config(f, "chip", i) != 0) {
426 if (parse_section(f, "chip", i) != 0) {
431 memcpy(&chipsptr[i], &chip_conf, sizeof(chip_conf));
433 /* Try to create chip with config parsed */
434 debug("CHIP:\nNUM=%d\nCTRL_NUM=%d\nDEVID=%d\nMANID=%d\n"
435 "PAGE_SZ=%d\nOOBSZ=%d\nREAD_T=%d\nDEVMODEL=%s\n"
436 "MAN=%s\nCOLADDRCYCLES=%d\nROWADDRCYCLES=%d\nCHWIDTH=%d\n"
437 "PGS/BLK=%d\nBLK/LUN=%d\nLUNS=%d\nERR_RATIO=%d\n"
438 "WEARLEVEL=%d\nISWP=%d\n\n\n\n",
439 chipsptr[i].num, chipsptr[i].ctrl_num,
440 chipsptr[i].device_id, chipsptr[i].manufact_id,
441 chipsptr[i].page_size, chipsptr[i].oob_size,
442 chipsptr[i].read_time, chipsptr[i].device_model,
443 chipsptr[i].manufacturer, chipsptr[i].col_addr_cycles,
444 chipsptr[i].row_addr_cycles, chipsptr[i].width,
445 chipsptr[i].pgs_per_blk, chipsptr[i].blks_per_lun,
446 chipsptr[i].luns, chipsptr[i].error_ratio,
447 chipsptr[i].wear_level, chipsptr[i].is_wp);
455 destroy_chips(struct sim_chip *chips)
462 parse_config(char *cfgfname, const char *devfname)
465 unsigned int chipsectionscnt, ctrlsectionscnt, i;
467 struct sim_chip *chips;
468 struct sim_ctrl *ctrls;
470 err = rc_open(cfgfname, "r", &f);
472 error("could not open configuration file (%s)", cfgfname);
476 /* First, try to configure simulator itself. */
477 if (configure_sim(devfname, f) != EX_OK) {
482 debug("SIM CONFIGURED!\n");
483 /* Then create controllers' configs */
484 if (create_ctrls(f, &ctrls, &ctrlsectionscnt) != 0) {
488 debug("CTRLS CONFIG READ!\n");
490 /* Then create chips' configs */
491 if (create_chips(f, &chips, &chipsectionscnt) != 0) {
492 destroy_ctrls(ctrls);
496 debug("CHIPS CONFIG READ!\n");
498 if (validate_ctrls(ctrls, ctrlsectionscnt) != 0) {
499 destroy_ctrls(ctrls);
500 destroy_chips(chips);
502 return (EX_SOFTWARE);
504 if (validate_chips(chips, chipsectionscnt, ctrls,
505 ctrlsectionscnt) != 0) {
506 destroy_ctrls(ctrls);
507 destroy_chips(chips);
509 return (EX_SOFTWARE);
513 fd = open(devfname, O_RDWR);
515 error("could not open simulator device file (%s)!",
518 destroy_chips(chips);
519 destroy_ctrls(ctrls);
523 debug("SIM CONFIG STARTED!\n");
525 /* At this stage, both ctrls' and chips' configs should be valid */
526 for (i = 0; i < ctrlsectionscnt; i++) {
527 err = ioctl(fd, NANDSIM_CREATE_CTRL, &ctrls[i]);
530 error("Controller#%d already created\n",
532 else if (err == EINVAL)
533 error("Incorrect controller number (%d)\n",
536 error("Could not created controller#%d\n",
538 /* Errors during controller creation stops parsing */
541 destroy_ctrls(ctrls);
542 destroy_chips(chips);
545 debug("CTRL#%d CONFIG STARTED!\n", i);
548 for (i = 0; i < chipsectionscnt; i++) {
549 err = ioctl(fd, NANDSIM_CREATE_CHIP, &chips[i]);
552 error("Chip#%d for controller#%d already "
553 "created\n", chips[i].num,
555 else if (err == EINVAL)
556 error("Incorrect chip number (%d:%d)\n",
557 chips[i].num, chips[i].ctrl_num);
559 error("Could not create chip (%d:%d)\n",
560 chips[i].num, chips[i].ctrl_num);
561 error("Could not start chip#%d\n", i);
562 destroy_chips(chips);
563 destroy_ctrls(ctrls);
569 debug("CHIPS CONFIG STARTED!\n");
573 destroy_chips(chips);
574 destroy_ctrls(ctrls);
579 * Function tries to get appropriate value for given key, convert it to
580 * array of ints (of given size), and perform all the necessary checks and
584 get_argument_intarray(const char *sect_name, int sectno,
585 struct nandsim_key *key, struct rcfile *f)
587 char strbuf[STRBUFSIZ];
592 getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
596 if (key->mandatory != 0) {
597 error(MSG_MANDATORYKEYMISSING, key->keyname,
601 /* Non-mandatory key, not present -- skip */
604 cnt = parse_intarray((char *)&strbuf, &intbuf);
605 cnt = (cnt <= key->maxlength) ? cnt : key->maxlength;
607 for (i = 0; i < cnt; i++) {
608 if (SIZE(key->valuetype) == SIZE_8)
609 *((uint8_t *)(key->field) + i) =
611 else if (SIZE(key->valuetype) == SIZE_16)
612 *((uint16_t *)(key->field) + i) =
615 *((uint32_t *)(key->field) + i) =
623 * Function tries to get appropriate value for given key, convert it to
624 * int of certain length.
627 get_argument_int(const char *sect_name, int sectno, struct nandsim_key *key,
633 getres = rc_getint(f, sect_name, sectno, key->keyname, &val);
636 if (key->mandatory != 0) {
637 error(MSG_MANDATORYKEYMISSING, key->keyname,
642 /* Non-mandatory key, not present -- skip */
645 if (SIZE(key->valuetype) == SIZE_8)
646 *(uint8_t *)(key->field) = (uint8_t)val;
647 else if (SIZE(key->valuetype) == SIZE_16)
648 *(uint16_t *)(key->field) = (uint16_t)val;
650 *(uint32_t *)(key->field) = (uint32_t)val;
654 /* Function tries to get string value for given key */
656 get_argument_string(const char *sect_name, int sectno,
657 struct nandsim_key *key, struct rcfile *f)
659 char strbuf[STRBUFSIZ];
662 getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
666 if (key->mandatory != 0) {
667 error(MSG_MANDATORYKEYMISSING, key->keyname,
671 /* Non-mandatory key, not present -- skip */
674 strncpy(key->field, (char *)&strbuf, (size_t)(key->maxlength - 1));
678 /* Function tries to get on/off value for given key */
680 get_argument_bool(const char *sect_name, int sectno, struct nandsim_key *key,
685 getres = rc_getbool(f, sect_name, sectno, key->keyname, &val);
687 if (key->mandatory != 0) {
688 error(MSG_MANDATORYKEYMISSING, key->keyname,
692 /* Non-mandatory key, not present -- skip */
695 *(uint8_t *)key->field = (uint8_t)val;
700 parse_section(struct rcfile *f, const char *sect_name, int sectno)
702 struct nandsim_key *key;
703 struct nandsim_section *sect = (struct nandsim_section *)§ions;
710 if (strcmp(sect->name, sect_name) == 0)
717 debug("->Section: %s, Key: %s, type: %d, size: %d",
718 sect_name, key->keyname, TYPE(key->valuetype),
719 SIZE(key->valuetype)/2);
721 switch (TYPE(key->valuetype)) {
723 /* Single int value */
724 getres = get_argument_int(sect_name, sectno, key, f);
730 case VALUE_UINTARRAY:
732 getres = get_argument_intarray(sect_name,
741 getres = get_argument_string(sect_name, sectno, key,
749 /* Boolean value (true/false/on/off/yes/no) */
750 getres = get_argument_bool(sect_name, sectno, key,
758 } while ((++key)->keyname != NULL);
764 validate_chips(struct sim_chip *chips, int chipcnt,
765 struct sim_ctrl *ctrls, int ctrlcnt)
767 int cchipcnt, i, width, j, id, max;
770 for (chipcnt -= 1; chipcnt >= 0; chipcnt--) {
771 if (chips[chipcnt].num >= MAX_CTRL_CS) {
772 error("chip no. too high (%d)!!\n",
777 if (chips[chipcnt].ctrl_num >= MAX_SIM_DEV) {
778 error("controller no. too high (%d)!!\n",
779 chips[chipcnt].ctrl_num);
783 if (chips[chipcnt].width != 8 &&
784 chips[chipcnt].width != 16) {
785 error("invalid width:%d for chip#%d",
786 chips[chipcnt].width, chips[chipcnt].num);
790 /* Check if page size is > 512 and if its power of 2 */
791 if (chips[chipcnt].page_size < 512 ||
792 (chips[chipcnt].page_size &
793 (chips[chipcnt].page_size - 1)) != 0) {
794 error("invalid page size:%d for chip#%d at ctrl#%d!!"
795 "\n", chips[chipcnt].page_size,
797 chips[chipcnt].ctrl_num);
801 /* Check if controller no. ctrl_num is configured */
802 for (i = 0, id = -1; i < ctrlcnt && id == -1; i++)
803 if (ctrls[i].num == chips[chipcnt].ctrl_num)
806 if (i == ctrlcnt && id == -1) {
807 error("Missing configuration for controller %d"
808 " (at least one chip is connected to it)",
809 chips[chipcnt].ctrl_num);
813 * Controller is configured -> check oob_size
817 max = ctrls[id].ecc_layout[0];
818 while (i < MAX_ECC_BYTES &&
819 ctrls[id].ecc_layout[i] != 0xffff) {
821 if (ctrls[id].ecc_layout[i] > max)
822 max = ctrls[id].ecc_layout[i];
826 if (chips[chipcnt].oob_size < (unsigned)i) {
827 error("OOB size for chip#%d at ctrl#%d is "
828 "smaller than ecc layout length!",
830 chips[chipcnt].ctrl_num);
834 if (chips[chipcnt].oob_size < (unsigned)max) {
835 error("OOB size for chip#%d at ctrl#%d is "
836 "smaller than maximal ecc position in "
837 "defined layout!", chips[chipcnt].num,
838 chips[chipcnt].ctrl_num);
845 if ((chips[chipcnt].erase_time < DELAYTIME_MIN ||
846 chips[chipcnt].erase_time > DELAYTIME_MAX) &&
847 chips[chipcnt].erase_time != 0) {
848 error("Invalid erase time value for chip#%d at "
851 chips[chipcnt].ctrl_num);
855 if ((chips[chipcnt].prog_time < DELAYTIME_MIN ||
856 chips[chipcnt].prog_time > DELAYTIME_MAX) &&
857 chips[chipcnt].prog_time != 0) {
858 error("Invalid prog time value for chip#%d at "
861 chips[chipcnt].ctrl_num);
865 if ((chips[chipcnt].read_time < DELAYTIME_MIN ||
866 chips[chipcnt].read_time > DELAYTIME_MAX) &&
867 chips[chipcnt].read_time != 0) {
868 error("Invalid read time value for chip#%d at "
871 chips[chipcnt].ctrl_num);
875 /* Check if chips attached to the same controller, have same width */
876 for (i = 0; i < ctrlcnt; i++) {
878 for (j = 0; j < cchipcnt; j++) {
879 if (chips[j].ctrl_num == i) {
881 width = chips[j].width;
883 if (width != chips[j].width) {
884 error("Chips attached to "
885 "ctrl#%d have different "
898 validate_ctrls(struct sim_ctrl *ctrl, int ctrlcnt)
900 for (ctrlcnt -= 1; ctrlcnt >= 0; ctrlcnt--) {
901 if (ctrl[ctrlcnt].num > MAX_SIM_DEV) {
902 error("Controller no. too high (%d)!!\n",
906 if (ctrl[ctrlcnt].num_cs > MAX_CTRL_CS) {
907 error("Too many CS (%d)!!\n", ctrl[ctrlcnt].num_cs);
910 if (ctrl[ctrlcnt].ecc != 0 && ctrl[ctrlcnt].ecc != 1) {
911 error("ECC is set to neither 0 nor 1 !\n");
919 static int validate_section_config(struct rcfile *f, const char *sect_name,
922 struct nandsim_key *key;
923 struct nandsim_section *sect;
927 for (match = 0, sect = (struct nandsim_section *)§ions;
928 sect != NULL; sect++) {
929 if (strcmp(sect->name, sect_name) == 0) {
938 keys_tbl = rc_getkeys(f, sect_name, sectno);
939 if (keys_tbl == NULL)
942 for (i = 0; keys_tbl[i] != NULL; i++) {
946 if (strcmp(keys_tbl[i], key->keyname) == 0) {
950 } while ((++key)->keyname != NULL);
953 error("Invalid key in config file: %s\n", keys_tbl[i]);