1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (C) 2009-2012 Semihalf
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 *
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
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/usr.sbin/nandsim/nandsim_cfgparse.c 330449 2018-03-05 07:26:05Z eadler $");
31
32#include <sys/errno.h>
33#include <sys/ioctl.h>
34#include <sys/types.h>
35
36#include <dev/nand/nandsim.h>
37
38#include <ctype.h>
39#include <fcntl.h>
40#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
43#include <sysexits.h>
44#include <unistd.h>
45
46#include "nandsim_cfgparse.h"
47
48#define warn(fmt, args...) do { \
49    printf("WARNING: " fmt "\n", ##args); } while (0)
50
51#define error(fmt, args...) do { \
52    printf("ERROR: " fmt "\n", ##args); } while (0)
53
54#define MSG_MANDATORYKEYMISSING "mandatory key \"%s\" value belonging to " \
55    "section \"%s\" is missing!\n"
56
57#define DEBUG
58#undef DEBUG
59
60#ifdef DEBUG
61#define debug(fmt, args...) do { \
62    printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0)
63#else
64#define debug(fmt, args...) do {} while(0)
65#endif
66
67#define STRBUFSIZ 2000
68
69/* Macros extracts type and type size */
70#define TYPE(x) ((x) & 0xf8)
71#define SIZE(x) (((x) & 0x07))
72
73/* Erase/Prog/Read time max and min values */
74#define DELAYTIME_MIN	10000
75#define DELAYTIME_MAX	10000000
76
77/* Structure holding configuration for controller. */
78static struct sim_ctrl ctrl_conf;
79/* Structure holding configuration for chip. */
80static struct sim_chip chip_conf;
81
82static 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},
85
86	{"ecc_layout", 1, VALUE_UINTARRAY | SIZE_16,
87	    (void *)&ctrl_conf.ecc_layout, MAX_ECC_BYTES},
88
89	{"filename", 0, VALUE_STRING,
90	    (void *)&ctrl_conf.filename, FILENAME_SIZE},
91
92	{"ecc", 0, VALUE_BOOL, (void *)&ctrl_conf.ecc, 0},
93	{NULL, 0, 0, NULL, 0},
94};
95
96static 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,
99	    0},
100	{"device_id", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.device_id,
101	    0},
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,
105	    DEV_MODEL_STR_SIZE},
106	{"manufacturer", 0, VALUE_STRING, (void *)&chip_conf.manufacturer,
107	    MAN_STR_SIZE},
108	{"page_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.page_size,
109	    0},
110	{"oob_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.oob_size,
111	    0},
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,
129	    0},
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},
133};
134
135static struct nandsim_section sections[] = {
136	{"ctrl", (struct nandsim_key *)&nandsim_ctrl_keys},
137	{"chip", (struct nandsim_key *)&nandsim_chip_keys},
138	{NULL, NULL},
139};
140
141static uint8_t logoutputtoint(char *, int *);
142static uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int);
143static uint8_t validate_ctrls(struct sim_ctrl *, int);
144static int configure_sim(const char *, struct rcfile *);
145static int create_ctrls(struct rcfile *, struct sim_ctrl **, int *);
146static int create_chips(struct rcfile *, struct sim_chip **, int *);
147static void destroy_ctrls(struct sim_ctrl *);
148static void destroy_chips(struct sim_chip *);
149static int validate_section_config(struct rcfile *, const char *, int);
150
151int
152convert_argint(char *arg, int *value)
153{
154
155	if (arg == NULL || value == NULL)
156		return (EINVAL);
157
158	errno = 0;
159	*value = (int)strtol(arg, NULL, 0);
160	if (*value == 0 && errno != 0) {
161		error("Cannot convert to number argument \'%s\'", arg);
162		return (EINVAL);
163	}
164	return (0);
165}
166
167int
168convert_arguint(char *arg, unsigned int *value)
169{
170
171	if (arg == NULL || value == NULL)
172		return (EINVAL);
173
174	errno = 0;
175	*value = (unsigned int)strtol(arg, NULL, 0);
176	if (*value == 0 && errno != 0) {
177		error("Cannot convert to number argument \'%s\'", arg);
178		return (EINVAL);
179	}
180	return (0);
181}
182
183/* Parse given ',' separated list of bytes into buffer. */
184int
185parse_intarray(char *array, int **buffer)
186{
187	char *tmp, *tmpstr, *origstr;
188	unsigned int currbufp = 0, i;
189	unsigned int count = 0, from  = 0, to = 0;
190
191	/* Remove square braces */
192	if (array[0] == '[')
193		array ++;
194	if (array[strlen(array)-1] == ']')
195		array[strlen(array)-1] = ',';
196
197	from = strlen(array);
198	origstr = (char *)malloc(sizeof(char) * from);
199	strcpy(origstr, array);
200
201	tmpstr = (char *)strtok(array, ",");
202	/* First loop checks for how big int array we need to allocate */
203	while (tmpstr != NULL) {
204		errno = 0;
205		if ((tmp = strchr(tmpstr, '-')) != NULL) {
206			*tmp = ' ';
207			if (convert_arguint(tmpstr, &from) ||
208			    convert_arguint(tmp, &to)) {
209				free(origstr);
210				return (EINVAL);
211			}
212
213			count += to - from + 1;
214		} else {
215			if (convert_arguint(tmpstr, &from)) {
216				free(origstr);
217				return (EINVAL);
218			}
219			count++;
220		}
221		tmpstr = (char *)strtok(NULL, ",");
222	}
223
224	if (count == 0)
225		goto out;
226
227	/* Allocate buffer of ints */
228	tmpstr = (char *)strtok(origstr, ",");
229	*buffer = malloc(count * sizeof(int));
230
231	/* Second loop is just inserting converted values into int array */
232	while (tmpstr != NULL) {
233		errno = 0;
234		if ((tmp = strchr(tmpstr, '-')) != NULL) {
235			*tmp = ' ';
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;
241			continue;
242		}
243		errno = 0;
244		from = (int)strtol(tmpstr, NULL, 0);
245		(*buffer)[currbufp++] = from;
246		tmpstr = (char *)strtok(NULL, ",");
247	}
248out:
249	free(origstr);
250	return (count);
251}
252
253/* Convert logoutput strings literals into appropriate ints. */
254static uint8_t
255logoutputtoint(char *logoutput, int *output)
256{
257	int out;
258
259	if (strcmp(logoutput, "file") == 0)
260		out = NANDSIM_OUTPUT_FILE;
261
262	else if (strcmp(logoutput, "console") == 0)
263		out = NANDSIM_OUTPUT_CONSOLE;
264
265	else if (strcmp(logoutput, "ram") == 0)
266		out = NANDSIM_OUTPUT_RAM;
267
268	else if (strcmp(logoutput, "none") == 0)
269		out = NANDSIM_OUTPUT_NONE;
270	else
271		out = -1;
272
273	*output = out;
274
275	if (out == -1)
276		return (EINVAL);
277	else
278		return (0);
279}
280
281static int
282configure_sim(const char *devfname, struct rcfile *f)
283{
284	struct sim_param sim_conf;
285	char buf[255];
286	int err, tmpv, fd;
287
288	err = rc_getint(f, "sim", 0, "log_level", &tmpv);
289
290	if (tmpv < 0 || tmpv > 255 || err) {
291		error("Bad log level specified (%d)\n", tmpv);
292		return (ENOTSUP);
293	} else
294		sim_conf.log_level = tmpv;
295
296	rc_getstring(f, "sim", 0, "log_output", 255, (char *)&buf);
297
298	tmpv = -1;
299	err = logoutputtoint((char *)&buf, &tmpv);
300	if (err) {
301		error("Log output specified in config file does not seem to "
302		    "be valid (%s)!", (char *)&buf);
303		return (ENOTSUP);
304	}
305
306	sim_conf.log_output = tmpv;
307
308	fd = open(devfname, O_RDWR);
309	if (fd == -1) {
310		error("could not open simulator device file (%s)!",
311		    devfname);
312		return (EX_OSFILE);
313	}
314
315	err = ioctl(fd, NANDSIM_SIM_PARAM, &sim_conf);
316	if (err) {
317		error("simulator parameters could not be modified: %s",
318		    strerror(errno));
319		close(fd);
320		return (ENXIO);
321	}
322
323	close(fd);
324	return (EX_OK);
325}
326
327static int
328create_ctrls(struct rcfile *f, struct sim_ctrl **ctrls, int *cnt)
329{
330	int count, i;
331	struct sim_ctrl *ctrlsptr;
332
333	count = rc_getsectionscount(f, "ctrl");
334	if (count > MAX_SIM_DEV) {
335		error("Too many CTRL sections specified(%d)", count);
336		return (ENOTSUP);
337	} else if (count == 0) {
338		error("No ctrl sections specified");
339		return (ENOENT);
340	}
341
342	ctrlsptr = (struct sim_ctrl *)malloc(sizeof(struct sim_ctrl) * count);
343	if (ctrlsptr == NULL) {
344		error("Could not allocate memory for ctrl configuration");
345		return (ENOMEM);
346	}
347
348	for (i = 0; i < count; i++) {
349		bzero((void *)&ctrl_conf, sizeof(ctrl_conf));
350
351		/*
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.
355		 */
356		memset((void *)&ctrl_conf.ecc_layout, 0xff,
357		    sizeof(ctrl_conf.ecc_layout));
358
359		if (validate_section_config(f, "ctrl", i) != 0) {
360			free(ctrlsptr);
361			return (EINVAL);
362		}
363
364		if (parse_section(f, "ctrl", i) != 0) {
365			free(ctrlsptr);
366			return (EINVAL);
367		}
368
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]);
376	}
377	*cnt = count;
378	*ctrls = ctrlsptr;
379	return (0);
380}
381
382static void
383destroy_ctrls(struct sim_ctrl *ctrls)
384{
385
386	free(ctrls);
387}
388
389static int
390create_chips(struct rcfile *f, struct sim_chip **chips, int *cnt)
391{
392	struct sim_chip *chipsptr;
393	int count, i;
394
395	count = rc_getsectionscount(f, "chip");
396	if (count > (MAX_CTRL_CS * MAX_SIM_DEV)) {
397		error("Too many chip sections specified(%d)", count);
398		return (ENOTSUP);
399	} else if (count == 0) {
400		error("No chip sections specified");
401		return (ENOENT);
402	}
403
404	chipsptr = (struct sim_chip *)malloc(sizeof(struct sim_chip) * count);
405	if (chipsptr == NULL) {
406		error("Could not allocate memory for chip configuration");
407		return (ENOMEM);
408	}
409
410	for (i = 0; i < count; i++) {
411		bzero((void *)&chip_conf, sizeof(chip_conf));
412
413		/*
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.
417		 */
418		memset((void *)&chip_conf.bad_block_map, 0xff,
419		    sizeof(chip_conf.bad_block_map));
420
421		if (validate_section_config(f, "chip", i) != 0) {
422			free(chipsptr);
423			return (EINVAL);
424		}
425
426		if (parse_section(f, "chip", i) != 0) {
427			free(chipsptr);
428			return (EINVAL);
429		}
430
431		memcpy(&chipsptr[i], &chip_conf, sizeof(chip_conf));
432
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);
448	}
449	*cnt = count;
450	*chips = chipsptr;
451	return (0);
452}
453
454static void
455destroy_chips(struct sim_chip *chips)
456{
457
458	free(chips);
459}
460
461int
462parse_config(char *cfgfname, const char *devfname)
463{
464	int err = 0, fd;
465	unsigned int chipsectionscnt, ctrlsectionscnt, i;
466	struct rcfile *f;
467	struct sim_chip *chips;
468	struct sim_ctrl *ctrls;
469
470	err = rc_open(cfgfname, "r", &f);
471	if (err) {
472		error("could not open configuration file (%s)", cfgfname);
473		return (EX_NOINPUT);
474	}
475
476	/* First, try to configure simulator itself. */
477	if (configure_sim(devfname, f) != EX_OK) {
478		rc_close(f);
479		return (EINVAL);
480	}
481
482	debug("SIM CONFIGURED!\n");
483	/* Then create controllers' configs */
484	if (create_ctrls(f, &ctrls, &ctrlsectionscnt) != 0) {
485		rc_close(f);
486		return (ENXIO);
487	}
488	debug("CTRLS CONFIG READ!\n");
489
490	/* Then create chips' configs */
491	if (create_chips(f, &chips, &chipsectionscnt) != 0) {
492		destroy_ctrls(ctrls);
493		rc_close(f);
494		return (ENXIO);
495	}
496	debug("CHIPS CONFIG READ!\n");
497
498	if (validate_ctrls(ctrls, ctrlsectionscnt) != 0) {
499		destroy_ctrls(ctrls);
500		destroy_chips(chips);
501		rc_close(f);
502		return (EX_SOFTWARE);
503	}
504	if (validate_chips(chips, chipsectionscnt, ctrls,
505	    ctrlsectionscnt) != 0) {
506		destroy_ctrls(ctrls);
507		destroy_chips(chips);
508		rc_close(f);
509		return (EX_SOFTWARE);
510	}
511
512	/* Open device */
513	fd = open(devfname, O_RDWR);
514	if (fd == -1) {
515		error("could not open simulator device file (%s)!",
516		    devfname);
517		rc_close(f);
518		destroy_chips(chips);
519		destroy_ctrls(ctrls);
520		return (EX_OSFILE);
521	}
522
523	debug("SIM CONFIG STARTED!\n");
524
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]);
528		if (err) {
529			if (err == EEXIST)
530				error("Controller#%d already created\n",
531				    ctrls[i].num);
532			else if (err == EINVAL)
533				error("Incorrect controller number (%d)\n",
534				    ctrls[i].num);
535			else
536				error("Could not created controller#%d\n",
537				    ctrls[i].num);
538			/* Errors during controller creation stops parsing */
539			close(fd);
540			rc_close(f);
541			destroy_ctrls(ctrls);
542			destroy_chips(chips);
543			return (ENXIO);
544		}
545		debug("CTRL#%d CONFIG STARTED!\n", i);
546	}
547
548	for (i = 0; i < chipsectionscnt; i++) {
549		err = ioctl(fd, NANDSIM_CREATE_CHIP, &chips[i]);
550		if (err) {
551			if (err == EEXIST)
552				error("Chip#%d for controller#%d already "
553				    "created\n", chips[i].num,
554				    chips[i].ctrl_num);
555			else if (err == EINVAL)
556				error("Incorrect chip number (%d:%d)\n",
557				    chips[i].num, chips[i].ctrl_num);
558			else
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);
564			close(fd);
565			rc_close(f);
566			return (ENXIO);
567		}
568	}
569	debug("CHIPS CONFIG STARTED!\n");
570
571	close(fd);
572	rc_close(f);
573	destroy_chips(chips);
574	destroy_ctrls(ctrls);
575	return (0);
576}
577
578/*
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
581 * conversions.
582 */
583static int
584get_argument_intarray(const char *sect_name, int sectno,
585    struct nandsim_key *key, struct rcfile *f)
586{
587	char strbuf[STRBUFSIZ];
588	int *intbuf;
589	int getres;
590	uint32_t cnt, i = 0;
591
592	getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
593	    (char *)&strbuf);
594
595	if (getres != 0) {
596		if (key->mandatory != 0) {
597			error(MSG_MANDATORYKEYMISSING, key->keyname,
598			    sect_name);
599			return (EINVAL);
600		} else
601			/* Non-mandatory key, not present -- skip */
602			return (0);
603	}
604	cnt = parse_intarray((char *)&strbuf, &intbuf);
605	cnt = (cnt <= key->maxlength) ? cnt : key->maxlength;
606
607	for (i = 0; i < cnt; i++) {
608		if (SIZE(key->valuetype) == SIZE_8)
609			*((uint8_t *)(key->field) + i) =
610			    (uint8_t)intbuf[i];
611		else if (SIZE(key->valuetype) == SIZE_16)
612			*((uint16_t *)(key->field) + i) =
613			    (uint16_t)intbuf[i];
614		else
615			*((uint32_t *)(key->field) + i) =
616			    (uint32_t)intbuf[i];
617	}
618	free(intbuf);
619	return (0);
620}
621
622/*
623 *  Function tries to get appropriate value for given key, convert it to
624 *  int of certain length.
625 */
626static int
627get_argument_int(const char *sect_name, int sectno, struct nandsim_key *key,
628    struct rcfile *f)
629{
630	int getres;
631	uint32_t val;
632
633	getres = rc_getint(f, sect_name, sectno, key->keyname, &val);
634	if (getres != 0) {
635
636		if (key->mandatory != 0) {
637			error(MSG_MANDATORYKEYMISSING, key->keyname,
638			    sect_name);
639
640			return (EINVAL);
641		} else
642			/* Non-mandatory key, not present -- skip */
643			return (0);
644	}
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;
649	else
650		*(uint32_t *)(key->field) = (uint32_t)val;
651	return (0);
652}
653
654/* Function tries to get string value for given key */
655static int
656get_argument_string(const char *sect_name, int sectno,
657    struct nandsim_key *key, struct rcfile *f)
658{
659	char strbuf[STRBUFSIZ];
660	int getres;
661
662	getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
663	    strbuf);
664
665	if (getres != 0) {
666		if (key->mandatory != 0) {
667			error(MSG_MANDATORYKEYMISSING, key->keyname,
668			    sect_name);
669			return (1);
670		} else
671			/* Non-mandatory key, not present -- skip */
672			return (0);
673	}
674	strncpy(key->field, (char *)&strbuf, (size_t)(key->maxlength - 1));
675	return (0);
676}
677
678/* Function tries to get on/off value for given key */
679static int
680get_argument_bool(const char *sect_name, int sectno, struct nandsim_key *key,
681    struct rcfile *f)
682{
683	int getres, val;
684
685	getres = rc_getbool(f, sect_name, sectno, key->keyname, &val);
686	if (getres != 0) {
687		if (key->mandatory != 0) {
688			error(MSG_MANDATORYKEYMISSING, key->keyname,
689			    sect_name);
690			return (1);
691		} else
692			/* Non-mandatory key, not present -- skip */
693			return (0);
694	}
695	*(uint8_t *)key->field = (uint8_t)val;
696	return (0);
697}
698
699int
700parse_section(struct rcfile *f, const char *sect_name, int sectno)
701{
702	struct nandsim_key *key;
703	struct nandsim_section *sect = (struct nandsim_section *)&sections;
704	int getres = 0;
705
706	while (1) {
707		if (sect == NULL)
708			return (EINVAL);
709
710		if (strcmp(sect->name, sect_name) == 0)
711			break;
712		else
713			sect++;
714	}
715	key = sect->keys;
716	do {
717		debug("->Section: %s, Key: %s, type: %d, size: %d",
718		    sect_name, key->keyname, TYPE(key->valuetype),
719		    SIZE(key->valuetype)/2);
720
721		switch (TYPE(key->valuetype)) {
722		case VALUE_UINT:
723			/* Single int value */
724			getres = get_argument_int(sect_name, sectno, key, f);
725
726			if (getres != 0)
727				return (getres);
728
729			break;
730		case VALUE_UINTARRAY:
731			/* Array of ints */
732			getres = get_argument_intarray(sect_name,
733			    sectno, key, f);
734
735			if (getres != 0)
736				return (getres);
737
738			break;
739		case VALUE_STRING:
740			/* Array of chars */
741			getres = get_argument_string(sect_name, sectno, key,
742			    f);
743
744			if (getres != 0)
745				return (getres);
746
747			break;
748		case VALUE_BOOL:
749			/* Boolean value (true/false/on/off/yes/no) */
750			getres = get_argument_bool(sect_name, sectno, key,
751			    f);
752
753			if (getres != 0)
754				return (getres);
755
756			break;
757		}
758	} while ((++key)->keyname != NULL);
759
760	return (0);
761}
762
763static uint8_t
764validate_chips(struct sim_chip *chips, int chipcnt,
765    struct sim_ctrl *ctrls, int ctrlcnt)
766{
767	int cchipcnt, i, width, j, id, max;
768
769	cchipcnt = chipcnt;
770	for (chipcnt -= 1; chipcnt >= 0; chipcnt--) {
771		if (chips[chipcnt].num >= MAX_CTRL_CS) {
772			error("chip no. too high (%d)!!\n",
773			    chips[chipcnt].num);
774			return (EINVAL);
775		}
776
777		if (chips[chipcnt].ctrl_num >= MAX_SIM_DEV) {
778			error("controller no. too high (%d)!!\n",
779			    chips[chipcnt].ctrl_num);
780			return (EINVAL);
781		}
782
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);
787			return (EINVAL);
788		}
789
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,
796			    chips[chipcnt].num,
797			    chips[chipcnt].ctrl_num);
798			return (EINVAL);
799		}
800
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)
804				id = i;
805
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);
810			return (EINVAL);
811		} else {
812			/*
813			 * Controller is configured -> check oob_size
814			 * validity
815			 */
816			i = 0;
817			max = ctrls[id].ecc_layout[0];
818			while (i < MAX_ECC_BYTES &&
819			    ctrls[id].ecc_layout[i] != 0xffff) {
820
821				if (ctrls[id].ecc_layout[i] > max)
822					max = ctrls[id].ecc_layout[i];
823				i++;
824			}
825
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!",
829				    chips[chipcnt].num,
830				    chips[chipcnt].ctrl_num);
831				exit(EINVAL);
832			}
833
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);
839				exit(EINVAL);
840			}
841
842
843		}
844
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 "
849			    "ctrl#%d",
850			    chips[chipcnt].num,
851			    chips[chipcnt].ctrl_num);
852			return (EINVAL);
853		}
854
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 "
859			    "ctr#%d!",
860			    chips[chipcnt].num,
861			    chips[chipcnt].ctrl_num);
862			return (EINVAL);
863		}
864
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 "
869			    "ctrl#%d!",
870			    chips[chipcnt].num,
871			    chips[chipcnt].ctrl_num);
872			return (EINVAL);
873		}
874	}
875	/* Check if chips attached to the same controller, have same width */
876	for (i = 0; i < ctrlcnt; i++) {
877		width = -1;
878		for (j = 0; j < cchipcnt; j++) {
879			if (chips[j].ctrl_num == i) {
880				if (width == -1) {
881					width = chips[j].width;
882				} else {
883					if (width != chips[j].width) {
884						error("Chips attached to "
885						    "ctrl#%d have different "
886						    "widths!\n", i);
887						return (EINVAL);
888					}
889				}
890			}
891		}
892	}
893
894	return (0);
895}
896
897static uint8_t
898validate_ctrls(struct sim_ctrl *ctrl, int ctrlcnt)
899{
900	for (ctrlcnt -= 1; ctrlcnt >= 0; ctrlcnt--) {
901		if (ctrl[ctrlcnt].num > MAX_SIM_DEV) {
902			error("Controller no. too high (%d)!!\n",
903			    ctrl[ctrlcnt].num);
904			return (EINVAL);
905		}
906		if (ctrl[ctrlcnt].num_cs > MAX_CTRL_CS) {
907			error("Too many CS (%d)!!\n", ctrl[ctrlcnt].num_cs);
908			return (EINVAL);
909		}
910		if (ctrl[ctrlcnt].ecc != 0 && ctrl[ctrlcnt].ecc != 1) {
911			error("ECC is set to neither 0 nor 1 !\n");
912			return (EINVAL);
913		}
914	}
915
916	return (0);
917}
918
919static int validate_section_config(struct rcfile *f, const char *sect_name,
920    int sectno)
921{
922	struct nandsim_key *key;
923	struct nandsim_section *sect;
924	char **keys_tbl;
925	int i, match;
926
927	for (match = 0, sect = (struct nandsim_section *)&sections;
928	    sect != NULL; sect++) {
929		if (strcmp(sect->name, sect_name) == 0) {
930			match = 1;
931			break;
932		}
933	}
934
935	if (match == 0)
936		return (EINVAL);
937
938	keys_tbl = rc_getkeys(f, sect_name, sectno);
939	if (keys_tbl == NULL)
940		return (ENOMEM);
941
942	for (i = 0; keys_tbl[i] != NULL; i++) {
943		key = sect->keys;
944		match = 0;
945		do {
946			if (strcmp(keys_tbl[i], key->keyname) == 0) {
947				match = 1;
948				break;
949			}
950		} while ((++key)->keyname != NULL);
951
952		if (match == 0) {
953			error("Invalid key in config file: %s\n", keys_tbl[i]);
954			free(keys_tbl);
955			return (EINVAL);
956		}
957	}
958
959	free(keys_tbl);
960	return (0);
961}
962