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/12/usr.sbin/nandsim/nandsim_cfgparse.c 326276 2017-11-27 15:37:16Z pfg $");
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. */
78 static struct sim_ctrl ctrl_conf;
79 /* Structure holding configuration for chip. */
80 static struct sim_chip chip_conf;
81 
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},
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 
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,
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 
135 static 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 
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);
150 
151 int
convert_argint(char * arg,int * value)152 convert_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 
167 int
convert_arguint(char * arg,unsigned int * value)168 convert_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. */
184 int
parse_intarray(char * array,int ** buffer)185 parse_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 	}
248 out:
249 	free(origstr);
250 	return (count);
251 }
252 
253 /* Convert logoutput strings literals into appropriate ints. */
254 static uint8_t
logoutputtoint(char * logoutput,int * output)255 logoutputtoint(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 
281 static int
configure_sim(const char * devfname,struct rcfile * f)282 configure_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 
327 static int
create_ctrls(struct rcfile * f,struct sim_ctrl ** ctrls,int * cnt)328 create_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 
382 static void
destroy_ctrls(struct sim_ctrl * ctrls)383 destroy_ctrls(struct sim_ctrl *ctrls)
384 {
385 
386 	free(ctrls);
387 }
388 
389 static int
create_chips(struct rcfile * f,struct sim_chip ** chips,int * cnt)390 create_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 
454 static void
destroy_chips(struct sim_chip * chips)455 destroy_chips(struct sim_chip *chips)
456 {
457 
458 	free(chips);
459 }
460 
461 int
parse_config(char * cfgfname,const char * devfname)462 parse_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  */
583 static int
get_argument_intarray(const char * sect_name,int sectno,struct nandsim_key * key,struct rcfile * f)584 get_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  */
626 static int
get_argument_int(const char * sect_name,int sectno,struct nandsim_key * key,struct rcfile * f)627 get_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 */
655 static int
get_argument_string(const char * sect_name,int sectno,struct nandsim_key * key,struct rcfile * f)656 get_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 */
679 static int
get_argument_bool(const char * sect_name,int sectno,struct nandsim_key * key,struct rcfile * f)680 get_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 
699 int
parse_section(struct rcfile * f,const char * sect_name,int sectno)700 parse_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 
763 static uint8_t
validate_chips(struct sim_chip * chips,int chipcnt,struct sim_ctrl * ctrls,int ctrlcnt)764 validate_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 
897 static uint8_t
validate_ctrls(struct sim_ctrl * ctrl,int ctrlcnt)898 validate_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 
validate_section_config(struct rcfile * f,const char * sect_name,int sectno)919 static 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