1 /*-
2  * Copyright (C) 2009-2012 Semihalf
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: stable/10/usr.sbin/nandsim/nandsim_cfgparse.c 293290 2016-01-07 00:40:51Z bdrewery $");
29 
30 #include <sys/errno.h>
31 #include <sys/ioctl.h>
32 #include <sys/types.h>
33 
34 #include <dev/nand/nandsim.h>
35 
36 #include <ctype.h>
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <sysexits.h>
42 #include <unistd.h>
43 
44 #include "nandsim_cfgparse.h"
45 
46 #define warn(fmt, args...) do { \
47     printf("WARNING: " fmt "\n", ##args); } while (0)
48 
49 #define error(fmt, args...) do { \
50     printf("ERROR: " fmt "\n", ##args); } while (0)
51 
52 #define MSG_MANDATORYKEYMISSING "mandatory key \"%s\" value belonging to " \
53     "section \"%s\" is missing!\n"
54 
55 #define DEBUG
56 #undef DEBUG
57 
58 #ifdef DEBUG
59 #define debug(fmt, args...) do { \
60     printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0)
61 #else
62 #define debug(fmt, args...) do {} while(0)
63 #endif
64 
65 #define STRBUFSIZ 2000
66 
67 /* Macros extracts type and type size */
68 #define TYPE(x) ((x) & 0xf8)
69 #define SIZE(x) (((x) & 0x07))
70 
71 /* Erase/Prog/Read time max and min values */
72 #define DELAYTIME_MIN	10000
73 #define DELAYTIME_MAX	10000000
74 
75 /* Structure holding configuration for controller. */
76 static struct sim_ctrl ctrl_conf;
77 /* Structure holding configuration for chip. */
78 static struct sim_chip chip_conf;
79 
80 static struct nandsim_key nandsim_ctrl_keys[] = {
81 	{"num_cs", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num_cs, 0},
82 	{"ctrl_num", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num, 0},
83 
84 	{"ecc_layout", 1, VALUE_UINTARRAY | SIZE_16,
85 	    (void *)&ctrl_conf.ecc_layout, MAX_ECC_BYTES},
86 
87 	{"filename", 0, VALUE_STRING,
88 	    (void *)&ctrl_conf.filename, FILENAME_SIZE},
89 
90 	{"ecc", 0, VALUE_BOOL, (void *)&ctrl_conf.ecc, 0},
91 	{NULL, 0, 0, NULL, 0},
92 };
93 
94 static struct nandsim_key nandsim_chip_keys[] = {
95 	{"chip_cs", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.num, 0},
96 	{"chip_ctrl", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.ctrl_num,
97 	    0},
98 	{"device_id", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.device_id,
99 	    0},
100 	{"manufacturer_id", 1, VALUE_UINT | SIZE_8,
101 	    (void *)&chip_conf.manufact_id, 0},
102 	{"model", 0, VALUE_STRING, (void *)&chip_conf.device_model,
103 	    DEV_MODEL_STR_SIZE},
104 	{"manufacturer", 0, VALUE_STRING, (void *)&chip_conf.manufacturer,
105 	    MAN_STR_SIZE},
106 	{"page_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.page_size,
107 	    0},
108 	{"oob_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.oob_size,
109 	    0},
110 	{"pages_per_block", 1, VALUE_UINT | SIZE_32,
111 	    (void *)&chip_conf.pgs_per_blk, 0},
112 	{"blocks_per_lun", 1, VALUE_UINT | SIZE_32,
113 	    (void *)&chip_conf.blks_per_lun, 0},
114 	{"luns", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.luns, 0},
115 	{"column_addr_cycle", 1,VALUE_UINT | SIZE_8,
116 	    (void *)&chip_conf.col_addr_cycles, 0},
117 	{"row_addr_cycle", 1, VALUE_UINT | SIZE_8,
118 	    (void *)&chip_conf.row_addr_cycles, 0},
119 	{"program_time", 0, VALUE_UINT | SIZE_32,
120 	    (void *)&chip_conf.prog_time, 0},
121 	{"erase_time", 0, VALUE_UINT | SIZE_32,
122 	    (void *)&chip_conf.erase_time, 0},
123 	{"read_time", 0, VALUE_UINT | SIZE_32,
124 	    (void *)&chip_conf.read_time, 0},
125 	{"width", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.width, 0},
126 	{"wear_out", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.wear_level,
127 	    0},
128 	{"bad_block_map", 0, VALUE_UINTARRAY | SIZE_32,
129 	    (void *)&chip_conf.bad_block_map, MAX_BAD_BLOCKS},
130 	{NULL, 0, 0, NULL, 0},
131 };
132 
133 static struct nandsim_section sections[] = {
134 	{"ctrl", (struct nandsim_key *)&nandsim_ctrl_keys},
135 	{"chip", (struct nandsim_key *)&nandsim_chip_keys},
136 	{NULL, NULL},
137 };
138 
139 static uint8_t logoutputtoint(char *, int *);
140 static uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int);
141 static uint8_t validate_ctrls(struct sim_ctrl *, int);
142 static int configure_sim(const char *, struct rcfile *);
143 static int create_ctrls(struct rcfile *, struct sim_ctrl **, int *);
144 static int create_chips(struct rcfile *, struct sim_chip **, int *);
145 static void destroy_ctrls(struct sim_ctrl *);
146 static void destroy_chips(struct sim_chip *);
147 static int validate_section_config(struct rcfile *, const char *, int);
148 
149 int
convert_argint(char * arg,int * value)150 convert_argint(char *arg, int *value)
151 {
152 
153 	if (arg == NULL || value == NULL)
154 		return (EINVAL);
155 
156 	errno = 0;
157 	*value = (int)strtol(arg, NULL, 0);
158 	if (*value == 0 && errno != 0) {
159 		error("Cannot convert to number argument \'%s\'", arg);
160 		return (EINVAL);
161 	}
162 	return (0);
163 }
164 
165 int
convert_arguint(char * arg,unsigned int * value)166 convert_arguint(char *arg, unsigned int *value)
167 {
168 
169 	if (arg == NULL || value == NULL)
170 		return (EINVAL);
171 
172 	errno = 0;
173 	*value = (unsigned int)strtol(arg, NULL, 0);
174 	if (*value == 0 && errno != 0) {
175 		error("Cannot convert to number argument \'%s\'", arg);
176 		return (EINVAL);
177 	}
178 	return (0);
179 }
180 
181 /* Parse given ',' separated list of bytes into buffer. */
182 int
parse_intarray(char * array,int ** buffer)183 parse_intarray(char *array, int **buffer)
184 {
185 	char *tmp, *tmpstr, *origstr;
186 	unsigned int currbufp = 0, i;
187 	unsigned int count = 0, from  = 0, to = 0;
188 
189 	/* Remove square braces */
190 	if (array[0] == '[')
191 		array ++;
192 	if (array[strlen(array)-1] == ']')
193 		array[strlen(array)-1] = ',';
194 
195 	from = strlen(array);
196 	origstr = (char *)malloc(sizeof(char) * from);
197 	strcpy(origstr, array);
198 
199 	tmpstr = (char *)strtok(array, ",");
200 	/* First loop checks for how big int array we need to allocate */
201 	while (tmpstr != NULL) {
202 		errno = 0;
203 		if ((tmp = strchr(tmpstr, '-')) != NULL) {
204 			*tmp = ' ';
205 			if (convert_arguint(tmpstr, &from) ||
206 			    convert_arguint(tmp, &to)) {
207 				free(origstr);
208 				return (EINVAL);
209 			}
210 
211 			count += to - from + 1;
212 		} else {
213 			if (convert_arguint(tmpstr, &from)) {
214 				free(origstr);
215 				return (EINVAL);
216 			}
217 			count++;
218 		}
219 		tmpstr = (char *)strtok(NULL, ",");
220 	}
221 
222 	if (count == 0)
223 		goto out;
224 
225 	/* Allocate buffer of ints */
226 	tmpstr = (char *)strtok(origstr, ",");
227 	*buffer = malloc(count * sizeof(int));
228 
229 	/* Second loop is just inserting converted values into int array */
230 	while (tmpstr != NULL) {
231 		errno = 0;
232 		if ((tmp = strchr(tmpstr, '-')) != NULL) {
233 			*tmp = ' ';
234 			from = strtol(tmpstr, NULL, 0);
235 			to = strtol(tmp, NULL, 0);
236 			tmpstr = strtok(NULL, ",");
237 			for (i = from; i <= to; i ++)
238 				(*buffer)[currbufp++] = i;
239 			continue;
240 		}
241 		errno = 0;
242 		from = (int)strtol(tmpstr, NULL, 0);
243 		(*buffer)[currbufp++] = from;
244 		tmpstr = (char *)strtok(NULL, ",");
245 	}
246 out:
247 	free(origstr);
248 	return (count);
249 }
250 
251 /* Convert logoutput strings literals into appropriate ints. */
252 static uint8_t
logoutputtoint(char * logoutput,int * output)253 logoutputtoint(char *logoutput, int *output)
254 {
255 	int out;
256 
257 	if (strcmp(logoutput, "file") == 0)
258 		out = NANDSIM_OUTPUT_FILE;
259 
260 	else if (strcmp(logoutput, "console") == 0)
261 		out = NANDSIM_OUTPUT_CONSOLE;
262 
263 	else if (strcmp(logoutput, "ram") == 0)
264 		out = NANDSIM_OUTPUT_RAM;
265 
266 	else if (strcmp(logoutput, "none") == 0)
267 		out = NANDSIM_OUTPUT_NONE;
268 	else
269 		out = -1;
270 
271 	*output = out;
272 
273 	if (out == -1)
274 		return (EINVAL);
275 	else
276 		return (0);
277 }
278 
279 static int
configure_sim(const char * devfname,struct rcfile * f)280 configure_sim(const char *devfname, struct rcfile *f)
281 {
282 	struct sim_param sim_conf;
283 	char buf[255];
284 	int err, tmpv, fd;
285 
286 	err = rc_getint(f, "sim", 0, "log_level", &tmpv);
287 
288 	if (tmpv < 0 || tmpv > 255 || err) {
289 		error("Bad log level specified (%d)\n", tmpv);
290 		return (ENOTSUP);
291 	} else
292 		sim_conf.log_level = tmpv;
293 
294 	rc_getstring(f, "sim", 0, "log_output", 255, (char *)&buf);
295 
296 	tmpv = -1;
297 	err = logoutputtoint((char *)&buf, &tmpv);
298 	if (err) {
299 		error("Log output specified in config file does not seem to "
300 		    "be valid (%s)!", (char *)&buf);
301 		return (ENOTSUP);
302 	}
303 
304 	sim_conf.log_output = tmpv;
305 
306 	fd = open(devfname, O_RDWR);
307 	if (fd == -1) {
308 		error("could not open simulator device file (%s)!",
309 		    devfname);
310 		return (EX_OSFILE);
311 	}
312 
313 	err = ioctl(fd, NANDSIM_SIM_PARAM, &sim_conf);
314 	if (err) {
315 		error("simulator parameters could not be modified: %s",
316 		    strerror(errno));
317 		close(fd);
318 		return (ENXIO);
319 	}
320 
321 	close(fd);
322 	return (EX_OK);
323 }
324 
325 static int
create_ctrls(struct rcfile * f,struct sim_ctrl ** ctrls,int * cnt)326 create_ctrls(struct rcfile *f, struct sim_ctrl **ctrls, int *cnt)
327 {
328 	int count, i;
329 	struct sim_ctrl *ctrlsptr;
330 
331 	count = rc_getsectionscount(f, "ctrl");
332 	if (count > MAX_SIM_DEV) {
333 		error("Too many CTRL sections specified(%d)", count);
334 		return (ENOTSUP);
335 	} else if (count == 0) {
336 		error("No ctrl sections specified");
337 		return (ENOENT);
338 	}
339 
340 	ctrlsptr = (struct sim_ctrl *)malloc(sizeof(struct sim_ctrl) * count);
341 	if (ctrlsptr == NULL) {
342 		error("Could not allocate memory for ctrl configuration");
343 		return (ENOMEM);
344 	}
345 
346 	for (i = 0; i < count; i++) {
347 		bzero((void *)&ctrl_conf, sizeof(ctrl_conf));
348 
349 		/*
350 		 * ECC layout have to end up with 0xffff, so
351 		 * we're filling buffer with 0xff. If ecc_layout is
352 		 * defined in config file, values will be overridden.
353 		 */
354 		memset((void *)&ctrl_conf.ecc_layout, 0xff,
355 		    sizeof(ctrl_conf.ecc_layout));
356 
357 		if (validate_section_config(f, "ctrl", i) != 0) {
358 			free(ctrlsptr);
359 			return (EINVAL);
360 		}
361 
362 		if (parse_section(f, "ctrl", i) != 0) {
363 			free(ctrlsptr);
364 			return (EINVAL);
365 		}
366 
367 		memcpy(&ctrlsptr[i], &ctrl_conf, sizeof(ctrl_conf));
368 		/* Try to create ctrl with config parsed */
369 		debug("NUM=%d\nNUM_CS=%d\nECC=%d\nFILENAME=%s\nECC_LAYOUT[0]"
370 		    "=%d\nECC_LAYOUT[1]=%d\n\n",
371 		    ctrlsptr[i].num, ctrlsptr[i].num_cs, ctrlsptr[i].ecc,
372 		    ctrlsptr[i].filename, ctrlsptr[i].ecc_layout[0],
373 		    ctrlsptr[i].ecc_layout[1]);
374 	}
375 	*cnt = count;
376 	*ctrls = ctrlsptr;
377 	return (0);
378 }
379 
380 static void
destroy_ctrls(struct sim_ctrl * ctrls)381 destroy_ctrls(struct sim_ctrl *ctrls)
382 {
383 
384 	free(ctrls);
385 }
386 
387 static int
create_chips(struct rcfile * f,struct sim_chip ** chips,int * cnt)388 create_chips(struct rcfile *f, struct sim_chip **chips, int *cnt)
389 {
390 	struct sim_chip *chipsptr;
391 	int count, i;
392 
393 	count = rc_getsectionscount(f, "chip");
394 	if (count > (MAX_CTRL_CS * MAX_SIM_DEV)) {
395 		error("Too many chip sections specified(%d)", count);
396 		return (ENOTSUP);
397 	} else if (count == 0) {
398 		error("No chip sections specified");
399 		return (ENOENT);
400 	}
401 
402 	chipsptr = (struct sim_chip *)malloc(sizeof(struct sim_chip) * count);
403 	if (chipsptr == NULL) {
404 		error("Could not allocate memory for chip configuration");
405 		return (ENOMEM);
406 	}
407 
408 	for (i = 0; i < count; i++) {
409 		bzero((void *)&chip_conf, sizeof(chip_conf));
410 
411 		/*
412 		 * Bad block map have to end up with 0xffff, so
413 		 * we're filling array with 0xff. If bad block map is
414 		 * defined in config file, values will be overridden.
415 		 */
416 		memset((void *)&chip_conf.bad_block_map, 0xff,
417 		    sizeof(chip_conf.bad_block_map));
418 
419 		if (validate_section_config(f, "chip", i) != 0) {
420 			free(chipsptr);
421 			return (EINVAL);
422 		}
423 
424 		if (parse_section(f, "chip", i) != 0) {
425 			free(chipsptr);
426 			return (EINVAL);
427 		}
428 
429 		memcpy(&chipsptr[i], &chip_conf, sizeof(chip_conf));
430 
431 		/* Try to create chip with config parsed */
432 		debug("CHIP:\nNUM=%d\nCTRL_NUM=%d\nDEVID=%d\nMANID=%d\n"
433 		    "PAGE_SZ=%d\nOOBSZ=%d\nREAD_T=%d\nDEVMODEL=%s\n"
434 		    "MAN=%s\nCOLADDRCYCLES=%d\nROWADDRCYCLES=%d\nCHWIDTH=%d\n"
435 		    "PGS/BLK=%d\nBLK/LUN=%d\nLUNS=%d\nERR_RATIO=%d\n"
436 		    "WEARLEVEL=%d\nISWP=%d\n\n\n\n",
437 		    chipsptr[i].num, chipsptr[i].ctrl_num,
438 		    chipsptr[i].device_id, chipsptr[i].manufact_id,
439 		    chipsptr[i].page_size, chipsptr[i].oob_size,
440 		    chipsptr[i].read_time, chipsptr[i].device_model,
441 		    chipsptr[i].manufacturer, chipsptr[i].col_addr_cycles,
442 		    chipsptr[i].row_addr_cycles, chipsptr[i].width,
443 		    chipsptr[i].pgs_per_blk, chipsptr[i].blks_per_lun,
444 		    chipsptr[i].luns, chipsptr[i].error_ratio,
445 		    chipsptr[i].wear_level, chipsptr[i].is_wp);
446 	}
447 	*cnt = count;
448 	*chips = chipsptr;
449 	return (0);
450 }
451 
452 static void
destroy_chips(struct sim_chip * chips)453 destroy_chips(struct sim_chip *chips)
454 {
455 
456 	free(chips);
457 }
458 
459 int
parse_config(char * cfgfname,const char * devfname)460 parse_config(char *cfgfname, const char *devfname)
461 {
462 	int err = 0, fd;
463 	unsigned int chipsectionscnt, ctrlsectionscnt, i;
464 	struct rcfile *f;
465 	struct sim_chip *chips;
466 	struct sim_ctrl *ctrls;
467 
468 	err = rc_open(cfgfname, "r", &f);
469 	if (err) {
470 		error("could not open configuration file (%s)", cfgfname);
471 		return (EX_NOINPUT);
472 	}
473 
474 	/* First, try to configure simulator itself. */
475 	if (configure_sim(devfname, f) != EX_OK) {
476 		rc_close(f);
477 		return (EINVAL);
478 	}
479 
480 	debug("SIM CONFIGURED!\n");
481 	/* Then create controllers' configs */
482 	if (create_ctrls(f, &ctrls, &ctrlsectionscnt) != 0) {
483 		rc_close(f);
484 		return (ENXIO);
485 	}
486 	debug("CTRLS CONFIG READ!\n");
487 
488 	/* Then create chips' configs */
489 	if (create_chips(f, &chips, &chipsectionscnt) != 0) {
490 		destroy_ctrls(ctrls);
491 		rc_close(f);
492 		return (ENXIO);
493 	}
494 	debug("CHIPS CONFIG READ!\n");
495 
496 	if (validate_ctrls(ctrls, ctrlsectionscnt) != 0) {
497 		destroy_ctrls(ctrls);
498 		destroy_chips(chips);
499 		rc_close(f);
500 		return (EX_SOFTWARE);
501 	}
502 	if (validate_chips(chips, chipsectionscnt, ctrls,
503 	    ctrlsectionscnt) != 0) {
504 		destroy_ctrls(ctrls);
505 		destroy_chips(chips);
506 		rc_close(f);
507 		return (EX_SOFTWARE);
508 	}
509 
510 	/* Open device */
511 	fd = open(devfname, O_RDWR);
512 	if (fd == -1) {
513 		error("could not open simulator device file (%s)!",
514 		    devfname);
515 		rc_close(f);
516 		destroy_chips(chips);
517 		destroy_ctrls(ctrls);
518 		return (EX_OSFILE);
519 	}
520 
521 	debug("SIM CONFIG STARTED!\n");
522 
523 	/* At this stage, both ctrls' and chips' configs should be valid */
524 	for (i = 0; i < ctrlsectionscnt; i++) {
525 		err = ioctl(fd, NANDSIM_CREATE_CTRL, &ctrls[i]);
526 		if (err) {
527 			if (err == EEXIST)
528 				error("Controller#%d already created\n",
529 				    ctrls[i].num);
530 			else if (err == EINVAL)
531 				error("Incorrect controler number (%d)\n",
532 				    ctrls[i].num);
533 			else
534 				error("Could not created controller#%d\n",
535 				    ctrls[i].num);
536 			/* Errors during controller creation stops parsing */
537 			close(fd);
538 			rc_close(f);
539 			destroy_ctrls(ctrls);
540 			destroy_chips(chips);
541 			return (ENXIO);
542 		}
543 		debug("CTRL#%d CONFIG STARTED!\n", i);
544 	}
545 
546 	for (i = 0; i < chipsectionscnt; i++) {
547 		err = ioctl(fd, NANDSIM_CREATE_CHIP, &chips[i]);
548 		if (err) {
549 			if (err == EEXIST)
550 				error("Chip#%d for controller#%d already "
551 				    "created\n", chips[i].num,
552 				    chips[i].ctrl_num);
553 			else if (err == EINVAL)
554 				error("Incorrect chip number (%d:%d)\n",
555 				    chips[i].num, chips[i].ctrl_num);
556 			else
557 				error("Could not create chip (%d:%d)\n",
558 				    chips[i].num, chips[i].ctrl_num);
559 			error("Could not start chip#%d\n", i);
560 			destroy_chips(chips);
561 			destroy_ctrls(ctrls);
562 			close(fd);
563 			rc_close(f);
564 			return (ENXIO);
565 		}
566 	}
567 	debug("CHIPS CONFIG STARTED!\n");
568 
569 	close(fd);
570 	rc_close(f);
571 	destroy_chips(chips);
572 	destroy_ctrls(ctrls);
573 	return (0);
574 }
575 
576 /*
577  * Function tries to get appropriate value for given key, convert it to
578  * array of ints (of given size), and perform all the necessary checks and
579  * conversions.
580  */
581 static int
get_argument_intarray(const char * sect_name,int sectno,struct nandsim_key * key,struct rcfile * f)582 get_argument_intarray(const char *sect_name, int sectno,
583     struct nandsim_key *key, struct rcfile *f)
584 {
585 	char strbuf[STRBUFSIZ];
586 	int *intbuf;
587 	int getres;
588 	uint32_t cnt, i = 0;
589 
590 	getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
591 	    (char *)&strbuf);
592 
593 	if (getres != 0) {
594 		if (key->mandatory != 0) {
595 			error(MSG_MANDATORYKEYMISSING, key->keyname,
596 			    sect_name);
597 			return (EINVAL);
598 		} else
599 			/* Non-mandatory key, not present -- skip */
600 			return (0);
601 	}
602 	cnt = parse_intarray((char *)&strbuf, &intbuf);
603 	cnt = (cnt <= key->maxlength) ? cnt : key->maxlength;
604 
605 	for (i = 0; i < cnt; i++) {
606 		if (SIZE(key->valuetype) == SIZE_8)
607 			*((uint8_t *)(key->field) + i) =
608 			    (uint8_t)intbuf[i];
609 		else if (SIZE(key->valuetype) == SIZE_16)
610 			*((uint16_t *)(key->field) + i) =
611 			    (uint16_t)intbuf[i];
612 		else
613 			*((uint32_t *)(key->field) + i) =
614 			    (uint32_t)intbuf[i];
615 	}
616 	free(intbuf);
617 	return (0);
618 }
619 
620 /*
621  *  Function tries to get appropriate value for given key, convert it to
622  *  int of certain length.
623  */
624 static int
get_argument_int(const char * sect_name,int sectno,struct nandsim_key * key,struct rcfile * f)625 get_argument_int(const char *sect_name, int sectno, struct nandsim_key *key,
626     struct rcfile *f)
627 {
628 	int getres;
629 	uint32_t val;
630 
631 	getres = rc_getint(f, sect_name, sectno, key->keyname, &val);
632 	if (getres != 0) {
633 
634 		if (key->mandatory != 0) {
635 			error(MSG_MANDATORYKEYMISSING, key->keyname,
636 			    sect_name);
637 
638 			return (EINVAL);
639 		} else
640 			/* Non-mandatory key, not present -- skip */
641 			return (0);
642 	}
643 	if (SIZE(key->valuetype) == SIZE_8)
644 		*(uint8_t *)(key->field) = (uint8_t)val;
645 	else if (SIZE(key->valuetype) == SIZE_16)
646 		*(uint16_t *)(key->field) = (uint16_t)val;
647 	else
648 		*(uint32_t *)(key->field) = (uint32_t)val;
649 	return (0);
650 }
651 
652 /* Function tries to get string value for given key */
653 static int
get_argument_string(const char * sect_name,int sectno,struct nandsim_key * key,struct rcfile * f)654 get_argument_string(const char *sect_name, int sectno,
655     struct nandsim_key *key, struct rcfile *f)
656 {
657 	char strbuf[STRBUFSIZ];
658 	int getres;
659 
660 	getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
661 	    strbuf);
662 
663 	if (getres != 0) {
664 		if (key->mandatory != 0) {
665 			error(MSG_MANDATORYKEYMISSING, key->keyname,
666 			    sect_name);
667 			return (1);
668 		} else
669 			/* Non-mandatory key, not present -- skip */
670 			return (0);
671 	}
672 	strncpy(key->field, (char *)&strbuf, (size_t)(key->maxlength - 1));
673 	return (0);
674 }
675 
676 /* Function tries to get on/off value for given key */
677 static int
get_argument_bool(const char * sect_name,int sectno,struct nandsim_key * key,struct rcfile * f)678 get_argument_bool(const char *sect_name, int sectno, struct nandsim_key *key,
679     struct rcfile *f)
680 {
681 	int getres, val;
682 
683 	getres = rc_getbool(f, sect_name, sectno, key->keyname, &val);
684 	if (getres != 0) {
685 		if (key->mandatory != 0) {
686 			error(MSG_MANDATORYKEYMISSING, key->keyname,
687 			    sect_name);
688 			return (1);
689 		} else
690 			/* Non-mandatory key, not present -- skip */
691 			return (0);
692 	}
693 	*(uint8_t *)key->field = (uint8_t)val;
694 	return (0);
695 }
696 
697 int
parse_section(struct rcfile * f,const char * sect_name,int sectno)698 parse_section(struct rcfile *f, const char *sect_name, int sectno)
699 {
700 	struct nandsim_key *key;
701 	struct nandsim_section *sect = (struct nandsim_section *)&sections;
702 	int getres = 0;
703 
704 	while (1) {
705 		if (sect == NULL)
706 			return (EINVAL);
707 
708 		if (strcmp(sect->name, sect_name) == 0)
709 			break;
710 		else
711 			sect++;
712 	}
713 	key = sect->keys;
714 	do {
715 		debug("->Section: %s, Key: %s, type: %d, size: %d",
716 		    sect_name, key->keyname, TYPE(key->valuetype),
717 		    SIZE(key->valuetype)/2);
718 
719 		switch (TYPE(key->valuetype)) {
720 		case VALUE_UINT:
721 			/* Single int value */
722 			getres = get_argument_int(sect_name, sectno, key, f);
723 
724 			if (getres != 0)
725 				return (getres);
726 
727 			break;
728 		case VALUE_UINTARRAY:
729 			/* Array of ints */
730 			getres = get_argument_intarray(sect_name,
731 			    sectno, key, f);
732 
733 			if (getres != 0)
734 				return (getres);
735 
736 			break;
737 		case VALUE_STRING:
738 			/* Array of chars */
739 			getres = get_argument_string(sect_name, sectno, key,
740 			    f);
741 
742 			if (getres != 0)
743 				return (getres);
744 
745 			break;
746 		case VALUE_BOOL:
747 			/* Boolean value (true/false/on/off/yes/no) */
748 			getres = get_argument_bool(sect_name, sectno, key,
749 			    f);
750 
751 			if (getres != 0)
752 				return (getres);
753 
754 			break;
755 		}
756 	} while ((++key)->keyname != NULL);
757 
758 	return (0);
759 }
760 
761 static uint8_t
validate_chips(struct sim_chip * chips,int chipcnt,struct sim_ctrl * ctrls,int ctrlcnt)762 validate_chips(struct sim_chip *chips, int chipcnt,
763     struct sim_ctrl *ctrls, int ctrlcnt)
764 {
765 	int cchipcnt, i, width, j, id, max;
766 
767 	cchipcnt = chipcnt;
768 	for (chipcnt -= 1; chipcnt >= 0; chipcnt--) {
769 		if (chips[chipcnt].num >= MAX_CTRL_CS) {
770 			error("chip no. too high (%d)!!\n",
771 			    chips[chipcnt].num);
772 			return (EINVAL);
773 		}
774 
775 		if (chips[chipcnt].ctrl_num >= MAX_SIM_DEV) {
776 			error("controller no. too high (%d)!!\n",
777 			    chips[chipcnt].ctrl_num);
778 			return (EINVAL);
779 		}
780 
781 		if (chips[chipcnt].width != 8 &&
782 		    chips[chipcnt].width != 16) {
783 			error("invalid width:%d for chip#%d",
784 			    chips[chipcnt].width, chips[chipcnt].num);
785 			return (EINVAL);
786 		}
787 
788 		/* Check if page size is > 512 and if its power of 2 */
789 		if (chips[chipcnt].page_size < 512 ||
790 		    (chips[chipcnt].page_size &
791 		    (chips[chipcnt].page_size - 1)) != 0) {
792 			error("invalid page size:%d for chip#%d at ctrl#%d!!"
793 			    "\n", chips[chipcnt].page_size,
794 			    chips[chipcnt].num,
795 			    chips[chipcnt].ctrl_num);
796 			return (EINVAL);
797 		}
798 
799 		/* Check if controller no. ctrl_num is configured */
800 		for (i = 0, id = -1; i < ctrlcnt && id == -1; i++)
801 			if (ctrls[i].num == chips[chipcnt].ctrl_num)
802 				id = i;
803 
804 		if (i == ctrlcnt && id == -1) {
805 			error("Missing configuration for controller %d"
806 			    " (at least one chip is connected to it)",
807 			    chips[chipcnt].ctrl_num);
808 			return (EINVAL);
809 		} else {
810 			/*
811 			 * Controller is configured -> check oob_size
812 			 * validity
813 			 */
814 			i = 0;
815 			max = ctrls[id].ecc_layout[0];
816 			while (i < MAX_ECC_BYTES &&
817 			    ctrls[id].ecc_layout[i] != 0xffff) {
818 
819 				if (ctrls[id].ecc_layout[i] > max)
820 					max = ctrls[id].ecc_layout[i];
821 				i++;
822 			}
823 
824 			if (chips[chipcnt].oob_size < (unsigned)i) {
825 				error("OOB size for chip#%d at ctrl#%d is "
826 				    "smaller than ecc layout length!",
827 				    chips[chipcnt].num,
828 				    chips[chipcnt].ctrl_num);
829 				exit(EINVAL);
830 			}
831 
832 			if (chips[chipcnt].oob_size < (unsigned)max) {
833 				error("OOB size for chip#%d at ctrl#%d is "
834 				    "smaller than maximal ecc position in "
835 				    "defined layout!", chips[chipcnt].num,
836 				    chips[chipcnt].ctrl_num);
837 				exit(EINVAL);
838 			}
839 
840 
841 		}
842 
843 		if ((chips[chipcnt].erase_time < DELAYTIME_MIN ||
844 		    chips[chipcnt].erase_time > DELAYTIME_MAX) &&
845 		    chips[chipcnt].erase_time != 0) {
846 			error("Invalid erase time value for chip#%d at "
847 			    "ctrl#%d",
848 			    chips[chipcnt].num,
849 			    chips[chipcnt].ctrl_num);
850 			return (EINVAL);
851 		}
852 
853 		if ((chips[chipcnt].prog_time < DELAYTIME_MIN ||
854 		    chips[chipcnt].prog_time > DELAYTIME_MAX) &&
855 		    chips[chipcnt].prog_time != 0) {
856 			error("Invalid prog time value for chip#%d at "
857 			    "ctr#%d!",
858 			    chips[chipcnt].num,
859 			    chips[chipcnt].ctrl_num);
860 			return (EINVAL);
861 		}
862 
863 		if ((chips[chipcnt].read_time < DELAYTIME_MIN ||
864 		    chips[chipcnt].read_time > DELAYTIME_MAX) &&
865 		    chips[chipcnt].read_time != 0) {
866 			error("Invalid read time value for chip#%d at "
867 			    "ctrl#%d!",
868 			    chips[chipcnt].num,
869 			    chips[chipcnt].ctrl_num);
870 			return (EINVAL);
871 		}
872 	}
873 	/* Check if chips attached to the same controller, have same width */
874 	for (i = 0; i < ctrlcnt; i++) {
875 		width = -1;
876 		for (j = 0; j < cchipcnt; j++) {
877 			if (chips[j].ctrl_num == i) {
878 				if (width == -1) {
879 					width = chips[j].width;
880 				} else {
881 					if (width != chips[j].width) {
882 						error("Chips attached to "
883 						    "ctrl#%d have different "
884 						    "widths!\n", i);
885 						return (EINVAL);
886 					}
887 				}
888 			}
889 		}
890 	}
891 
892 	return (0);
893 }
894 
895 static uint8_t
validate_ctrls(struct sim_ctrl * ctrl,int ctrlcnt)896 validate_ctrls(struct sim_ctrl *ctrl, int ctrlcnt)
897 {
898 	for (ctrlcnt -= 1; ctrlcnt >= 0; ctrlcnt--) {
899 		if (ctrl[ctrlcnt].num > MAX_SIM_DEV) {
900 			error("Controller no. too high (%d)!!\n",
901 			    ctrl[ctrlcnt].num);
902 			return (EINVAL);
903 		}
904 		if (ctrl[ctrlcnt].num_cs > MAX_CTRL_CS) {
905 			error("Too many CS (%d)!!\n", ctrl[ctrlcnt].num_cs);
906 			return (EINVAL);
907 		}
908 		if (ctrl[ctrlcnt].ecc != 0 && ctrl[ctrlcnt].ecc != 1) {
909 			error("ECC is set to neither 0 nor 1 !\n");
910 			return (EINVAL);
911 		}
912 	}
913 
914 	return (0);
915 }
916 
validate_section_config(struct rcfile * f,const char * sect_name,int sectno)917 static int validate_section_config(struct rcfile *f, const char *sect_name,
918     int sectno)
919 {
920 	struct nandsim_key *key;
921 	struct nandsim_section *sect;
922 	char **keys_tbl;
923 	int i, match;
924 
925 	for (match = 0, sect = (struct nandsim_section *)&sections;
926 	    sect != NULL; sect++) {
927 		if (strcmp(sect->name, sect_name) == 0) {
928 			match = 1;
929 			break;
930 		}
931 	}
932 
933 	if (match == 0)
934 		return (EINVAL);
935 
936 	keys_tbl = rc_getkeys(f, sect_name, sectno);
937 	if (keys_tbl == NULL)
938 		return (ENOMEM);
939 
940 	for (i = 0; keys_tbl[i] != NULL; i++) {
941 		key = sect->keys;
942 		match = 0;
943 		do {
944 			if (strcmp(keys_tbl[i], key->keyname) == 0) {
945 				match = 1;
946 				break;
947 			}
948 		} while ((++key)->keyname != NULL);
949 
950 		if (match == 0) {
951 			error("Invalid key in config file: %s\n", keys_tbl[i]);
952 			free(keys_tbl);
953 			return (EINVAL);
954 		}
955 	}
956 
957 	free(keys_tbl);
958 	return (0);
959 }
960