1235537Sgber/*-
2235537Sgber * Copyright (C) 2009-2012 Semihalf
3235537Sgber * All rights reserved.
4235537Sgber *
5235537Sgber * Redistribution and use in source and binary forms, with or without
6235537Sgber * modification, are permitted provided that the following conditions
7235537Sgber * are met:
8235537Sgber * 1. Redistributions of source code must retain the above copyright
9235537Sgber *    notice, this list of conditions and the following disclaimer.
10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright
11235537Sgber *    notice, this list of conditions and the following disclaimer in the
12235537Sgber *    documentation and/or other materials provided with the distribution.
13235537Sgber *
14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17235537Sgber * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24235537Sgber * SUCH DAMAGE.
25235537Sgber */
26235607Sgber
27235607Sgber#include <sys/cdefs.h>
28235537Sgber__FBSDID("$FreeBSD: releng/10.3/usr.sbin/nandsim/nandsim_cfgparse.c 293290 2016-01-07 00:40:51Z bdrewery $");
29235537Sgber
30235537Sgber#include <sys/errno.h>
31235537Sgber#include <sys/ioctl.h>
32235537Sgber#include <sys/types.h>
33235537Sgber
34235537Sgber#include <dev/nand/nandsim.h>
35235537Sgber
36235537Sgber#include <ctype.h>
37235537Sgber#include <fcntl.h>
38235537Sgber#include <stdio.h>
39235537Sgber#include <string.h>
40235537Sgber#include <stdlib.h>
41235537Sgber#include <sysexits.h>
42235537Sgber#include <unistd.h>
43235537Sgber
44235537Sgber#include "nandsim_cfgparse.h"
45235537Sgber
46235537Sgber#define warn(fmt, args...) do { \
47235537Sgber    printf("WARNING: " fmt "\n", ##args); } while (0)
48235537Sgber
49235537Sgber#define error(fmt, args...) do { \
50235537Sgber    printf("ERROR: " fmt "\n", ##args); } while (0)
51235537Sgber
52235537Sgber#define MSG_MANDATORYKEYMISSING "mandatory key \"%s\" value belonging to " \
53235537Sgber    "section \"%s\" is missing!\n"
54235537Sgber
55235537Sgber#define DEBUG
56235537Sgber#undef DEBUG
57235537Sgber
58235537Sgber#ifdef DEBUG
59235537Sgber#define debug(fmt, args...) do { \
60235537Sgber    printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0)
61235537Sgber#else
62235537Sgber#define debug(fmt, args...) do {} while(0)
63235537Sgber#endif
64235537Sgber
65235537Sgber#define STRBUFSIZ 2000
66235537Sgber
67235537Sgber/* Macros extracts type and type size */
68235537Sgber#define TYPE(x) ((x) & 0xf8)
69235537Sgber#define SIZE(x) (((x) & 0x07))
70235537Sgber
71235537Sgber/* Erase/Prog/Read time max and min values */
72235537Sgber#define DELAYTIME_MIN	10000
73235537Sgber#define DELAYTIME_MAX	10000000
74235537Sgber
75235537Sgber/* Structure holding configuration for controller. */
76235537Sgberstatic struct sim_ctrl ctrl_conf;
77235537Sgber/* Structure holding configuration for chip. */
78235537Sgberstatic struct sim_chip chip_conf;
79235537Sgber
80235537Sgberstatic struct nandsim_key nandsim_ctrl_keys[] = {
81235537Sgber	{"num_cs", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num_cs, 0},
82235537Sgber	{"ctrl_num", 1, VALUE_UINT | SIZE_8, (void *)&ctrl_conf.num, 0},
83235537Sgber
84235537Sgber	{"ecc_layout", 1, VALUE_UINTARRAY | SIZE_16,
85235537Sgber	    (void *)&ctrl_conf.ecc_layout, MAX_ECC_BYTES},
86235537Sgber
87235537Sgber	{"filename", 0, VALUE_STRING,
88235537Sgber	    (void *)&ctrl_conf.filename, FILENAME_SIZE},
89235537Sgber
90235537Sgber	{"ecc", 0, VALUE_BOOL, (void *)&ctrl_conf.ecc, 0},
91235537Sgber	{NULL, 0, 0, NULL, 0},
92235537Sgber};
93235537Sgber
94235537Sgberstatic struct nandsim_key nandsim_chip_keys[] = {
95235537Sgber	{"chip_cs", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.num, 0},
96235537Sgber	{"chip_ctrl", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.ctrl_num,
97235537Sgber	    0},
98235537Sgber	{"device_id", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.device_id,
99235537Sgber	    0},
100235537Sgber	{"manufacturer_id", 1, VALUE_UINT | SIZE_8,
101235537Sgber	    (void *)&chip_conf.manufact_id, 0},
102235537Sgber	{"model", 0, VALUE_STRING, (void *)&chip_conf.device_model,
103235537Sgber	    DEV_MODEL_STR_SIZE},
104235537Sgber	{"manufacturer", 0, VALUE_STRING, (void *)&chip_conf.manufacturer,
105235537Sgber	    MAN_STR_SIZE},
106235537Sgber	{"page_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.page_size,
107235537Sgber	    0},
108235537Sgber	{"oob_size", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.oob_size,
109235537Sgber	    0},
110235537Sgber	{"pages_per_block", 1, VALUE_UINT | SIZE_32,
111235537Sgber	    (void *)&chip_conf.pgs_per_blk, 0},
112235537Sgber	{"blocks_per_lun", 1, VALUE_UINT | SIZE_32,
113235537Sgber	    (void *)&chip_conf.blks_per_lun, 0},
114235537Sgber	{"luns", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.luns, 0},
115235537Sgber	{"column_addr_cycle", 1,VALUE_UINT | SIZE_8,
116235537Sgber	    (void *)&chip_conf.col_addr_cycles, 0},
117235537Sgber	{"row_addr_cycle", 1, VALUE_UINT | SIZE_8,
118235537Sgber	    (void *)&chip_conf.row_addr_cycles, 0},
119235537Sgber	{"program_time", 0, VALUE_UINT | SIZE_32,
120235537Sgber	    (void *)&chip_conf.prog_time, 0},
121235537Sgber	{"erase_time", 0, VALUE_UINT | SIZE_32,
122235537Sgber	    (void *)&chip_conf.erase_time, 0},
123235537Sgber	{"read_time", 0, VALUE_UINT | SIZE_32,
124235537Sgber	    (void *)&chip_conf.read_time, 0},
125235537Sgber	{"width", 1, VALUE_UINT | SIZE_8, (void *)&chip_conf.width, 0},
126235537Sgber	{"wear_out", 1, VALUE_UINT | SIZE_32, (void *)&chip_conf.wear_level,
127235537Sgber	    0},
128235537Sgber	{"bad_block_map", 0, VALUE_UINTARRAY | SIZE_32,
129235537Sgber	    (void *)&chip_conf.bad_block_map, MAX_BAD_BLOCKS},
130235537Sgber	{NULL, 0, 0, NULL, 0},
131235537Sgber};
132235537Sgber
133249744Sedstatic struct nandsim_section sections[] = {
134235537Sgber	{"ctrl", (struct nandsim_key *)&nandsim_ctrl_keys},
135235537Sgber	{"chip", (struct nandsim_key *)&nandsim_chip_keys},
136235537Sgber	{NULL, NULL},
137235537Sgber};
138235537Sgber
139235537Sgberstatic uint8_t logoutputtoint(char *, int *);
140235537Sgberstatic uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int);
141235537Sgberstatic uint8_t validate_ctrls(struct sim_ctrl *, int);
142235537Sgberstatic int configure_sim(const char *, struct rcfile *);
143235537Sgberstatic int create_ctrls(struct rcfile *, struct sim_ctrl **, int *);
144235537Sgberstatic int create_chips(struct rcfile *, struct sim_chip **, int *);
145235537Sgberstatic void destroy_ctrls(struct sim_ctrl *);
146235537Sgberstatic void destroy_chips(struct sim_chip *);
147235537Sgberstatic int validate_section_config(struct rcfile *, const char *, int);
148235537Sgber
149235537Sgberint
150235537Sgberconvert_argint(char *arg, int *value)
151235537Sgber{
152235537Sgber
153235537Sgber	if (arg == NULL || value == NULL)
154235537Sgber		return (EINVAL);
155235537Sgber
156235537Sgber	errno = 0;
157235537Sgber	*value = (int)strtol(arg, NULL, 0);
158235537Sgber	if (*value == 0 && errno != 0) {
159235537Sgber		error("Cannot convert to number argument \'%s\'", arg);
160235537Sgber		return (EINVAL);
161235537Sgber	}
162235537Sgber	return (0);
163235537Sgber}
164235537Sgber
165235537Sgberint
166235537Sgberconvert_arguint(char *arg, unsigned int *value)
167235537Sgber{
168235537Sgber
169235537Sgber	if (arg == NULL || value == NULL)
170235537Sgber		return (EINVAL);
171235537Sgber
172235537Sgber	errno = 0;
173235537Sgber	*value = (unsigned int)strtol(arg, NULL, 0);
174235537Sgber	if (*value == 0 && errno != 0) {
175235537Sgber		error("Cannot convert to number argument \'%s\'", arg);
176235537Sgber		return (EINVAL);
177235537Sgber	}
178235537Sgber	return (0);
179235537Sgber}
180235537Sgber
181235537Sgber/* Parse given ',' separated list of bytes into buffer. */
182235537Sgberint
183235537Sgberparse_intarray(char *array, int **buffer)
184235537Sgber{
185235537Sgber	char *tmp, *tmpstr, *origstr;
186235537Sgber	unsigned int currbufp = 0, i;
187235537Sgber	unsigned int count = 0, from  = 0, to = 0;
188235537Sgber
189235537Sgber	/* Remove square braces */
190235537Sgber	if (array[0] == '[')
191235537Sgber		array ++;
192235537Sgber	if (array[strlen(array)-1] == ']')
193235537Sgber		array[strlen(array)-1] = ',';
194235537Sgber
195235537Sgber	from = strlen(array);
196235537Sgber	origstr = (char *)malloc(sizeof(char) * from);
197235537Sgber	strcpy(origstr, array);
198235537Sgber
199235537Sgber	tmpstr = (char *)strtok(array, ",");
200235537Sgber	/* First loop checks for how big int array we need to allocate */
201235537Sgber	while (tmpstr != NULL) {
202235537Sgber		errno = 0;
203235537Sgber		if ((tmp = strchr(tmpstr, '-')) != NULL) {
204235537Sgber			*tmp = ' ';
205235537Sgber			if (convert_arguint(tmpstr, &from) ||
206235537Sgber			    convert_arguint(tmp, &to)) {
207235537Sgber				free(origstr);
208235537Sgber				return (EINVAL);
209235537Sgber			}
210235537Sgber
211235537Sgber			count += to - from + 1;
212235537Sgber		} else {
213235537Sgber			if (convert_arguint(tmpstr, &from)) {
214235537Sgber				free(origstr);
215235537Sgber				return (EINVAL);
216235537Sgber			}
217235537Sgber			count++;
218235537Sgber		}
219235537Sgber		tmpstr = (char *)strtok(NULL, ",");
220235537Sgber	}
221235537Sgber
222235537Sgber	if (count == 0)
223235537Sgber		goto out;
224235537Sgber
225235537Sgber	/* Allocate buffer of ints */
226235537Sgber	tmpstr = (char *)strtok(origstr, ",");
227235537Sgber	*buffer = malloc(count * sizeof(int));
228235537Sgber
229235537Sgber	/* Second loop is just inserting converted values into int array */
230235537Sgber	while (tmpstr != NULL) {
231235537Sgber		errno = 0;
232235537Sgber		if ((tmp = strchr(tmpstr, '-')) != NULL) {
233235537Sgber			*tmp = ' ';
234235537Sgber			from = strtol(tmpstr, NULL, 0);
235235537Sgber			to = strtol(tmp, NULL, 0);
236235537Sgber			tmpstr = strtok(NULL, ",");
237235537Sgber			for (i = from; i <= to; i ++)
238235537Sgber				(*buffer)[currbufp++] = i;
239235537Sgber			continue;
240235537Sgber		}
241235537Sgber		errno = 0;
242235537Sgber		from = (int)strtol(tmpstr, NULL, 0);
243235537Sgber		(*buffer)[currbufp++] = from;
244235537Sgber		tmpstr = (char *)strtok(NULL, ",");
245235537Sgber	}
246235537Sgberout:
247235537Sgber	free(origstr);
248235537Sgber	return (count);
249235537Sgber}
250235537Sgber
251235537Sgber/* Convert logoutput strings literals into appropriate ints. */
252235537Sgberstatic uint8_t
253235537Sgberlogoutputtoint(char *logoutput, int *output)
254235537Sgber{
255235537Sgber	int out;
256235537Sgber
257235537Sgber	if (strcmp(logoutput, "file") == 0)
258235537Sgber		out = NANDSIM_OUTPUT_FILE;
259235537Sgber
260235537Sgber	else if (strcmp(logoutput, "console") == 0)
261235537Sgber		out = NANDSIM_OUTPUT_CONSOLE;
262235537Sgber
263235537Sgber	else if (strcmp(logoutput, "ram") == 0)
264235537Sgber		out = NANDSIM_OUTPUT_RAM;
265235537Sgber
266235537Sgber	else if (strcmp(logoutput, "none") == 0)
267235537Sgber		out = NANDSIM_OUTPUT_NONE;
268235537Sgber	else
269235537Sgber		out = -1;
270235537Sgber
271235537Sgber	*output = out;
272235537Sgber
273235537Sgber	if (out == -1)
274235537Sgber		return (EINVAL);
275235537Sgber	else
276235537Sgber		return (0);
277235537Sgber}
278235537Sgber
279235537Sgberstatic int
280235537Sgberconfigure_sim(const char *devfname, struct rcfile *f)
281235537Sgber{
282235537Sgber	struct sim_param sim_conf;
283235537Sgber	char buf[255];
284235537Sgber	int err, tmpv, fd;
285235537Sgber
286235537Sgber	err = rc_getint(f, "sim", 0, "log_level", &tmpv);
287235537Sgber
288235537Sgber	if (tmpv < 0 || tmpv > 255 || err) {
289235537Sgber		error("Bad log level specified (%d)\n", tmpv);
290235537Sgber		return (ENOTSUP);
291235537Sgber	} else
292235537Sgber		sim_conf.log_level = tmpv;
293235537Sgber
294235537Sgber	rc_getstring(f, "sim", 0, "log_output", 255, (char *)&buf);
295235537Sgber
296235537Sgber	tmpv = -1;
297235537Sgber	err = logoutputtoint((char *)&buf, &tmpv);
298235537Sgber	if (err) {
299235537Sgber		error("Log output specified in config file does not seem to "
300235537Sgber		    "be valid (%s)!", (char *)&buf);
301235537Sgber		return (ENOTSUP);
302235537Sgber	}
303235537Sgber
304235537Sgber	sim_conf.log_output = tmpv;
305235537Sgber
306235537Sgber	fd = open(devfname, O_RDWR);
307235537Sgber	if (fd == -1) {
308235537Sgber		error("could not open simulator device file (%s)!",
309235537Sgber		    devfname);
310235537Sgber		return (EX_OSFILE);
311235537Sgber	}
312235537Sgber
313235537Sgber	err = ioctl(fd, NANDSIM_SIM_PARAM, &sim_conf);
314235537Sgber	if (err) {
315235537Sgber		error("simulator parameters could not be modified: %s",
316235537Sgber		    strerror(errno));
317235537Sgber		close(fd);
318235537Sgber		return (ENXIO);
319235537Sgber	}
320235537Sgber
321235537Sgber	close(fd);
322235537Sgber	return (EX_OK);
323235537Sgber}
324235537Sgber
325235537Sgberstatic int
326235537Sgbercreate_ctrls(struct rcfile *f, struct sim_ctrl **ctrls, int *cnt)
327235537Sgber{
328235537Sgber	int count, i;
329235537Sgber	struct sim_ctrl *ctrlsptr;
330235537Sgber
331235537Sgber	count = rc_getsectionscount(f, "ctrl");
332235537Sgber	if (count > MAX_SIM_DEV) {
333235537Sgber		error("Too many CTRL sections specified(%d)", count);
334235537Sgber		return (ENOTSUP);
335235537Sgber	} else if (count == 0) {
336235537Sgber		error("No ctrl sections specified");
337235537Sgber		return (ENOENT);
338235537Sgber	}
339235537Sgber
340235537Sgber	ctrlsptr = (struct sim_ctrl *)malloc(sizeof(struct sim_ctrl) * count);
341235537Sgber	if (ctrlsptr == NULL) {
342235537Sgber		error("Could not allocate memory for ctrl configuration");
343235537Sgber		return (ENOMEM);
344235537Sgber	}
345235537Sgber
346235537Sgber	for (i = 0; i < count; i++) {
347235537Sgber		bzero((void *)&ctrl_conf, sizeof(ctrl_conf));
348235537Sgber
349235537Sgber		/*
350235537Sgber		 * ECC layout have to end up with 0xffff, so
351235537Sgber		 * we're filling buffer with 0xff. If ecc_layout is
352293290Sbdrewery		 * defined in config file, values will be overridden.
353235537Sgber		 */
354235537Sgber		memset((void *)&ctrl_conf.ecc_layout, 0xff,
355235537Sgber		    sizeof(ctrl_conf.ecc_layout));
356235537Sgber
357235537Sgber		if (validate_section_config(f, "ctrl", i) != 0) {
358235537Sgber			free(ctrlsptr);
359235537Sgber			return (EINVAL);
360235537Sgber		}
361235537Sgber
362235537Sgber		if (parse_section(f, "ctrl", i) != 0) {
363235537Sgber			free(ctrlsptr);
364235537Sgber			return (EINVAL);
365235537Sgber		}
366235537Sgber
367235537Sgber		memcpy(&ctrlsptr[i], &ctrl_conf, sizeof(ctrl_conf));
368235537Sgber		/* Try to create ctrl with config parsed */
369235537Sgber		debug("NUM=%d\nNUM_CS=%d\nECC=%d\nFILENAME=%s\nECC_LAYOUT[0]"
370235537Sgber		    "=%d\nECC_LAYOUT[1]=%d\n\n",
371235537Sgber		    ctrlsptr[i].num, ctrlsptr[i].num_cs, ctrlsptr[i].ecc,
372235537Sgber		    ctrlsptr[i].filename, ctrlsptr[i].ecc_layout[0],
373235537Sgber		    ctrlsptr[i].ecc_layout[1]);
374235537Sgber	}
375235537Sgber	*cnt = count;
376235537Sgber	*ctrls = ctrlsptr;
377235537Sgber	return (0);
378235537Sgber}
379235537Sgber
380235537Sgberstatic void
381235537Sgberdestroy_ctrls(struct sim_ctrl *ctrls)
382235537Sgber{
383235537Sgber
384235537Sgber	free(ctrls);
385235537Sgber}
386235537Sgber
387235537Sgberstatic int
388235537Sgbercreate_chips(struct rcfile *f, struct sim_chip **chips, int *cnt)
389235537Sgber{
390235537Sgber	struct sim_chip *chipsptr;
391235537Sgber	int count, i;
392235537Sgber
393235537Sgber	count = rc_getsectionscount(f, "chip");
394235537Sgber	if (count > (MAX_CTRL_CS * MAX_SIM_DEV)) {
395235537Sgber		error("Too many chip sections specified(%d)", count);
396235537Sgber		return (ENOTSUP);
397235537Sgber	} else if (count == 0) {
398235537Sgber		error("No chip sections specified");
399235537Sgber		return (ENOENT);
400235537Sgber	}
401235537Sgber
402235537Sgber	chipsptr = (struct sim_chip *)malloc(sizeof(struct sim_chip) * count);
403235537Sgber	if (chipsptr == NULL) {
404235537Sgber		error("Could not allocate memory for chip configuration");
405235537Sgber		return (ENOMEM);
406235537Sgber	}
407235537Sgber
408235537Sgber	for (i = 0; i < count; i++) {
409235537Sgber		bzero((void *)&chip_conf, sizeof(chip_conf));
410235537Sgber
411235537Sgber		/*
412235537Sgber		 * Bad block map have to end up with 0xffff, so
413235537Sgber		 * we're filling array with 0xff. If bad block map is
414293290Sbdrewery		 * defined in config file, values will be overridden.
415235537Sgber		 */
416235537Sgber		memset((void *)&chip_conf.bad_block_map, 0xff,
417235537Sgber		    sizeof(chip_conf.bad_block_map));
418235537Sgber
419235537Sgber		if (validate_section_config(f, "chip", i) != 0) {
420235537Sgber			free(chipsptr);
421235537Sgber			return (EINVAL);
422235537Sgber		}
423235537Sgber
424235537Sgber		if (parse_section(f, "chip", i) != 0) {
425235537Sgber			free(chipsptr);
426235537Sgber			return (EINVAL);
427235537Sgber		}
428235537Sgber
429235537Sgber		memcpy(&chipsptr[i], &chip_conf, sizeof(chip_conf));
430235537Sgber
431235537Sgber		/* Try to create chip with config parsed */
432235537Sgber		debug("CHIP:\nNUM=%d\nCTRL_NUM=%d\nDEVID=%d\nMANID=%d\n"
433235537Sgber		    "PAGE_SZ=%d\nOOBSZ=%d\nREAD_T=%d\nDEVMODEL=%s\n"
434235537Sgber		    "MAN=%s\nCOLADDRCYCLES=%d\nROWADDRCYCLES=%d\nCHWIDTH=%d\n"
435235537Sgber		    "PGS/BLK=%d\nBLK/LUN=%d\nLUNS=%d\nERR_RATIO=%d\n"
436235537Sgber		    "WEARLEVEL=%d\nISWP=%d\n\n\n\n",
437235537Sgber		    chipsptr[i].num, chipsptr[i].ctrl_num,
438235537Sgber		    chipsptr[i].device_id, chipsptr[i].manufact_id,
439235537Sgber		    chipsptr[i].page_size, chipsptr[i].oob_size,
440235537Sgber		    chipsptr[i].read_time, chipsptr[i].device_model,
441235537Sgber		    chipsptr[i].manufacturer, chipsptr[i].col_addr_cycles,
442235537Sgber		    chipsptr[i].row_addr_cycles, chipsptr[i].width,
443235537Sgber		    chipsptr[i].pgs_per_blk, chipsptr[i].blks_per_lun,
444235537Sgber		    chipsptr[i].luns, chipsptr[i].error_ratio,
445235537Sgber		    chipsptr[i].wear_level, chipsptr[i].is_wp);
446235537Sgber	}
447235537Sgber	*cnt = count;
448235537Sgber	*chips = chipsptr;
449235537Sgber	return (0);
450235537Sgber}
451235537Sgber
452235537Sgberstatic void
453235537Sgberdestroy_chips(struct sim_chip *chips)
454235537Sgber{
455235537Sgber
456235537Sgber	free(chips);
457235537Sgber}
458235537Sgber
459235537Sgberint
460235537Sgberparse_config(char *cfgfname, const char *devfname)
461235537Sgber{
462235537Sgber	int err = 0, fd;
463235537Sgber	unsigned int chipsectionscnt, ctrlsectionscnt, i;
464235537Sgber	struct rcfile *f;
465235537Sgber	struct sim_chip *chips;
466235537Sgber	struct sim_ctrl *ctrls;
467235537Sgber
468235537Sgber	err = rc_open(cfgfname, "r", &f);
469235537Sgber	if (err) {
470235537Sgber		error("could not open configuration file (%s)", cfgfname);
471235537Sgber		return (EX_NOINPUT);
472235537Sgber	}
473235537Sgber
474235537Sgber	/* First, try to configure simulator itself. */
475235537Sgber	if (configure_sim(devfname, f) != EX_OK) {
476235537Sgber		rc_close(f);
477235537Sgber		return (EINVAL);
478235537Sgber	}
479235537Sgber
480235537Sgber	debug("SIM CONFIGURED!\n");
481235537Sgber	/* Then create controllers' configs */
482235537Sgber	if (create_ctrls(f, &ctrls, &ctrlsectionscnt) != 0) {
483235537Sgber		rc_close(f);
484235537Sgber		return (ENXIO);
485235537Sgber	}
486235537Sgber	debug("CTRLS CONFIG READ!\n");
487235537Sgber
488235537Sgber	/* Then create chips' configs */
489235537Sgber	if (create_chips(f, &chips, &chipsectionscnt) != 0) {
490235537Sgber		destroy_ctrls(ctrls);
491235537Sgber		rc_close(f);
492235537Sgber		return (ENXIO);
493235537Sgber	}
494235537Sgber	debug("CHIPS CONFIG READ!\n");
495235537Sgber
496235537Sgber	if (validate_ctrls(ctrls, ctrlsectionscnt) != 0) {
497235537Sgber		destroy_ctrls(ctrls);
498235537Sgber		destroy_chips(chips);
499235537Sgber		rc_close(f);
500235537Sgber		return (EX_SOFTWARE);
501235537Sgber	}
502235537Sgber	if (validate_chips(chips, chipsectionscnt, ctrls,
503235537Sgber	    ctrlsectionscnt) != 0) {
504235537Sgber		destroy_ctrls(ctrls);
505235537Sgber		destroy_chips(chips);
506235537Sgber		rc_close(f);
507235537Sgber		return (EX_SOFTWARE);
508235537Sgber	}
509235537Sgber
510235537Sgber	/* Open device */
511235537Sgber	fd = open(devfname, O_RDWR);
512235537Sgber	if (fd == -1) {
513235537Sgber		error("could not open simulator device file (%s)!",
514235537Sgber		    devfname);
515235537Sgber		rc_close(f);
516235537Sgber		destroy_chips(chips);
517235537Sgber		destroy_ctrls(ctrls);
518235537Sgber		return (EX_OSFILE);
519235537Sgber	}
520235537Sgber
521235537Sgber	debug("SIM CONFIG STARTED!\n");
522235537Sgber
523235537Sgber	/* At this stage, both ctrls' and chips' configs should be valid */
524235537Sgber	for (i = 0; i < ctrlsectionscnt; i++) {
525235537Sgber		err = ioctl(fd, NANDSIM_CREATE_CTRL, &ctrls[i]);
526235537Sgber		if (err) {
527235537Sgber			if (err == EEXIST)
528235537Sgber				error("Controller#%d already created\n",
529235537Sgber				    ctrls[i].num);
530235537Sgber			else if (err == EINVAL)
531235537Sgber				error("Incorrect controler number (%d)\n",
532235537Sgber				    ctrls[i].num);
533235537Sgber			else
534235537Sgber				error("Could not created controller#%d\n",
535235537Sgber				    ctrls[i].num);
536235537Sgber			/* Errors during controller creation stops parsing */
537235537Sgber			close(fd);
538235537Sgber			rc_close(f);
539235537Sgber			destroy_ctrls(ctrls);
540235537Sgber			destroy_chips(chips);
541235537Sgber			return (ENXIO);
542235537Sgber		}
543235537Sgber		debug("CTRL#%d CONFIG STARTED!\n", i);
544235537Sgber	}
545235537Sgber
546235537Sgber	for (i = 0; i < chipsectionscnt; i++) {
547235537Sgber		err = ioctl(fd, NANDSIM_CREATE_CHIP, &chips[i]);
548235537Sgber		if (err) {
549235537Sgber			if (err == EEXIST)
550235537Sgber				error("Chip#%d for controller#%d already "
551235537Sgber				    "created\n", chips[i].num,
552235537Sgber				    chips[i].ctrl_num);
553235537Sgber			else if (err == EINVAL)
554235537Sgber				error("Incorrect chip number (%d:%d)\n",
555235537Sgber				    chips[i].num, chips[i].ctrl_num);
556235537Sgber			else
557235537Sgber				error("Could not create chip (%d:%d)\n",
558235537Sgber				    chips[i].num, chips[i].ctrl_num);
559235537Sgber			error("Could not start chip#%d\n", i);
560235537Sgber			destroy_chips(chips);
561235537Sgber			destroy_ctrls(ctrls);
562235537Sgber			close(fd);
563235537Sgber			rc_close(f);
564235537Sgber			return (ENXIO);
565235537Sgber		}
566235537Sgber	}
567235537Sgber	debug("CHIPS CONFIG STARTED!\n");
568235537Sgber
569235537Sgber	close(fd);
570235537Sgber	rc_close(f);
571235537Sgber	destroy_chips(chips);
572235537Sgber	destroy_ctrls(ctrls);
573235537Sgber	return (0);
574235537Sgber}
575235537Sgber
576235537Sgber/*
577235537Sgber * Function tries to get appropriate value for given key, convert it to
578249583Sgabor * array of ints (of given size), and perform all the necessary checks and
579235537Sgber * conversions.
580235537Sgber */
581235537Sgberstatic int
582235537Sgberget_argument_intarray(const char *sect_name, int sectno,
583235537Sgber    struct nandsim_key *key, struct rcfile *f)
584235537Sgber{
585235537Sgber	char strbuf[STRBUFSIZ];
586235537Sgber	int *intbuf;
587235537Sgber	int getres;
588235537Sgber	uint32_t cnt, i = 0;
589235537Sgber
590235537Sgber	getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
591235537Sgber	    (char *)&strbuf);
592235537Sgber
593235537Sgber	if (getres != 0) {
594235537Sgber		if (key->mandatory != 0) {
595235537Sgber			error(MSG_MANDATORYKEYMISSING, key->keyname,
596235537Sgber			    sect_name);
597235537Sgber			return (EINVAL);
598235537Sgber		} else
599235537Sgber			/* Non-mandatory key, not present -- skip */
600235537Sgber			return (0);
601235537Sgber	}
602235537Sgber	cnt = parse_intarray((char *)&strbuf, &intbuf);
603235537Sgber	cnt = (cnt <= key->maxlength) ? cnt : key->maxlength;
604235537Sgber
605235537Sgber	for (i = 0; i < cnt; i++) {
606235537Sgber		if (SIZE(key->valuetype) == SIZE_8)
607235537Sgber			*((uint8_t *)(key->field) + i) =
608235537Sgber			    (uint8_t)intbuf[i];
609235537Sgber		else if (SIZE(key->valuetype) == SIZE_16)
610235537Sgber			*((uint16_t *)(key->field) + i) =
611235537Sgber			    (uint16_t)intbuf[i];
612235537Sgber		else
613235537Sgber			*((uint32_t *)(key->field) + i) =
614235537Sgber			    (uint32_t)intbuf[i];
615235537Sgber	}
616235537Sgber	free(intbuf);
617235537Sgber	return (0);
618235537Sgber}
619235537Sgber
620235537Sgber/*
621235537Sgber *  Function tries to get appropriate value for given key, convert it to
622235537Sgber *  int of certain length.
623235537Sgber */
624235537Sgberstatic int
625235537Sgberget_argument_int(const char *sect_name, int sectno, struct nandsim_key *key,
626235537Sgber    struct rcfile *f)
627235537Sgber{
628235537Sgber	int getres;
629235537Sgber	uint32_t val;
630235537Sgber
631235537Sgber	getres = rc_getint(f, sect_name, sectno, key->keyname, &val);
632235537Sgber	if (getres != 0) {
633235537Sgber
634235537Sgber		if (key->mandatory != 0) {
635235537Sgber			error(MSG_MANDATORYKEYMISSING, key->keyname,
636235537Sgber			    sect_name);
637235537Sgber
638235537Sgber			return (EINVAL);
639235537Sgber		} else
640235537Sgber			/* Non-mandatory key, not present -- skip */
641235537Sgber			return (0);
642235537Sgber	}
643235537Sgber	if (SIZE(key->valuetype) == SIZE_8)
644235537Sgber		*(uint8_t *)(key->field) = (uint8_t)val;
645235537Sgber	else if (SIZE(key->valuetype) == SIZE_16)
646235537Sgber		*(uint16_t *)(key->field) = (uint16_t)val;
647235537Sgber	else
648235537Sgber		*(uint32_t *)(key->field) = (uint32_t)val;
649235537Sgber	return (0);
650235537Sgber}
651235537Sgber
652235537Sgber/* Function tries to get string value for given key */
653235537Sgberstatic int
654235537Sgberget_argument_string(const char *sect_name, int sectno,
655235537Sgber    struct nandsim_key *key, struct rcfile *f)
656235537Sgber{
657235537Sgber	char strbuf[STRBUFSIZ];
658235537Sgber	int getres;
659235537Sgber
660235537Sgber	getres = rc_getstring(f, sect_name, sectno, key->keyname, STRBUFSIZ,
661235537Sgber	    strbuf);
662235537Sgber
663235537Sgber	if (getres != 0) {
664235537Sgber		if (key->mandatory != 0) {
665235537Sgber			error(MSG_MANDATORYKEYMISSING, key->keyname,
666235537Sgber			    sect_name);
667235537Sgber			return (1);
668235537Sgber		} else
669235537Sgber			/* Non-mandatory key, not present -- skip */
670235537Sgber			return (0);
671235537Sgber	}
672235537Sgber	strncpy(key->field, (char *)&strbuf, (size_t)(key->maxlength - 1));
673235537Sgber	return (0);
674235537Sgber}
675235537Sgber
676235537Sgber/* Function tries to get on/off value for given key */
677235537Sgberstatic int
678235537Sgberget_argument_bool(const char *sect_name, int sectno, struct nandsim_key *key,
679235537Sgber    struct rcfile *f)
680235537Sgber{
681235537Sgber	int getres, val;
682235537Sgber
683235537Sgber	getres = rc_getbool(f, sect_name, sectno, key->keyname, &val);
684235537Sgber	if (getres != 0) {
685235537Sgber		if (key->mandatory != 0) {
686235537Sgber			error(MSG_MANDATORYKEYMISSING, key->keyname,
687235537Sgber			    sect_name);
688235537Sgber			return (1);
689235537Sgber		} else
690235537Sgber			/* Non-mandatory key, not present -- skip */
691235537Sgber			return (0);
692235537Sgber	}
693235537Sgber	*(uint8_t *)key->field = (uint8_t)val;
694235537Sgber	return (0);
695235537Sgber}
696235537Sgber
697235537Sgberint
698235537Sgberparse_section(struct rcfile *f, const char *sect_name, int sectno)
699235537Sgber{
700235537Sgber	struct nandsim_key *key;
701235537Sgber	struct nandsim_section *sect = (struct nandsim_section *)&sections;
702235537Sgber	int getres = 0;
703235537Sgber
704235537Sgber	while (1) {
705235537Sgber		if (sect == NULL)
706235537Sgber			return (EINVAL);
707235537Sgber
708235537Sgber		if (strcmp(sect->name, sect_name) == 0)
709235537Sgber			break;
710235537Sgber		else
711235537Sgber			sect++;
712235537Sgber	}
713235537Sgber	key = sect->keys;
714235537Sgber	do {
715235537Sgber		debug("->Section: %s, Key: %s, type: %d, size: %d",
716235537Sgber		    sect_name, key->keyname, TYPE(key->valuetype),
717235537Sgber		    SIZE(key->valuetype)/2);
718235537Sgber
719235537Sgber		switch (TYPE(key->valuetype)) {
720235537Sgber		case VALUE_UINT:
721235537Sgber			/* Single int value */
722235537Sgber			getres = get_argument_int(sect_name, sectno, key, f);
723235537Sgber
724235537Sgber			if (getres != 0)
725235537Sgber				return (getres);
726235537Sgber
727235537Sgber			break;
728235537Sgber		case VALUE_UINTARRAY:
729235537Sgber			/* Array of ints */
730235537Sgber			getres = get_argument_intarray(sect_name,
731235537Sgber			    sectno, key, f);
732235537Sgber
733235537Sgber			if (getres != 0)
734235537Sgber				return (getres);
735235537Sgber
736235537Sgber			break;
737235537Sgber		case VALUE_STRING:
738235537Sgber			/* Array of chars */
739235537Sgber			getres = get_argument_string(sect_name, sectno, key,
740235537Sgber			    f);
741235537Sgber
742235537Sgber			if (getres != 0)
743235537Sgber				return (getres);
744235537Sgber
745235537Sgber			break;
746235537Sgber		case VALUE_BOOL:
747235537Sgber			/* Boolean value (true/false/on/off/yes/no) */
748235537Sgber			getres = get_argument_bool(sect_name, sectno, key,
749235537Sgber			    f);
750235537Sgber
751235537Sgber			if (getres != 0)
752235537Sgber				return (getres);
753235537Sgber
754235537Sgber			break;
755235537Sgber		}
756235537Sgber	} while ((++key)->keyname != NULL);
757235537Sgber
758235537Sgber	return (0);
759235537Sgber}
760235537Sgber
761235537Sgberstatic uint8_t
762235537Sgbervalidate_chips(struct sim_chip *chips, int chipcnt,
763235537Sgber    struct sim_ctrl *ctrls, int ctrlcnt)
764235537Sgber{
765235537Sgber	int cchipcnt, i, width, j, id, max;
766235537Sgber
767235537Sgber	cchipcnt = chipcnt;
768235537Sgber	for (chipcnt -= 1; chipcnt >= 0; chipcnt--) {
769235537Sgber		if (chips[chipcnt].num >= MAX_CTRL_CS) {
770235537Sgber			error("chip no. too high (%d)!!\n",
771235537Sgber			    chips[chipcnt].num);
772235537Sgber			return (EINVAL);
773235537Sgber		}
774235537Sgber
775235537Sgber		if (chips[chipcnt].ctrl_num >= MAX_SIM_DEV) {
776235537Sgber			error("controller no. too high (%d)!!\n",
777235537Sgber			    chips[chipcnt].ctrl_num);
778235537Sgber			return (EINVAL);
779235537Sgber		}
780235537Sgber
781235537Sgber		if (chips[chipcnt].width != 8 &&
782235537Sgber		    chips[chipcnt].width != 16) {
783235537Sgber			error("invalid width:%d for chip#%d",
784235537Sgber			    chips[chipcnt].width, chips[chipcnt].num);
785235537Sgber			return (EINVAL);
786235537Sgber		}
787235537Sgber
788235537Sgber		/* Check if page size is > 512 and if its power of 2 */
789235537Sgber		if (chips[chipcnt].page_size < 512 ||
790235537Sgber		    (chips[chipcnt].page_size &
791235537Sgber		    (chips[chipcnt].page_size - 1)) != 0) {
792235537Sgber			error("invalid page size:%d for chip#%d at ctrl#%d!!"
793235537Sgber			    "\n", chips[chipcnt].page_size,
794235537Sgber			    chips[chipcnt].num,
795235537Sgber			    chips[chipcnt].ctrl_num);
796235537Sgber			return (EINVAL);
797235537Sgber		}
798235537Sgber
799235537Sgber		/* Check if controller no. ctrl_num is configured */
800235537Sgber		for (i = 0, id = -1; i < ctrlcnt && id == -1; i++)
801235537Sgber			if (ctrls[i].num == chips[chipcnt].ctrl_num)
802235537Sgber				id = i;
803235537Sgber
804235537Sgber		if (i == ctrlcnt && id == -1) {
805235537Sgber			error("Missing configuration for controller %d"
806235537Sgber			    " (at least one chip is connected to it)",
807235537Sgber			    chips[chipcnt].ctrl_num);
808235537Sgber			return (EINVAL);
809235537Sgber		} else {
810235537Sgber			/*
811235537Sgber			 * Controller is configured -> check oob_size
812235537Sgber			 * validity
813235537Sgber			 */
814235537Sgber			i = 0;
815235537Sgber			max = ctrls[id].ecc_layout[0];
816235537Sgber			while (i < MAX_ECC_BYTES &&
817235537Sgber			    ctrls[id].ecc_layout[i] != 0xffff) {
818235537Sgber
819235537Sgber				if (ctrls[id].ecc_layout[i] > max)
820235537Sgber					max = ctrls[id].ecc_layout[i];
821235537Sgber				i++;
822235537Sgber			}
823235537Sgber
824235537Sgber			if (chips[chipcnt].oob_size < (unsigned)i) {
825235537Sgber				error("OOB size for chip#%d at ctrl#%d is "
826235537Sgber				    "smaller than ecc layout length!",
827235537Sgber				    chips[chipcnt].num,
828235537Sgber				    chips[chipcnt].ctrl_num);
829235537Sgber				exit(EINVAL);
830235537Sgber			}
831235537Sgber
832235537Sgber			if (chips[chipcnt].oob_size < (unsigned)max) {
833235537Sgber				error("OOB size for chip#%d at ctrl#%d is "
834235537Sgber				    "smaller than maximal ecc position in "
835235537Sgber				    "defined layout!", chips[chipcnt].num,
836235537Sgber				    chips[chipcnt].ctrl_num);
837235537Sgber				exit(EINVAL);
838235537Sgber			}
839235537Sgber
840235537Sgber
841235537Sgber		}
842235537Sgber
843235537Sgber		if ((chips[chipcnt].erase_time < DELAYTIME_MIN ||
844235537Sgber		    chips[chipcnt].erase_time > DELAYTIME_MAX) &&
845235537Sgber		    chips[chipcnt].erase_time != 0) {
846235537Sgber			error("Invalid erase time value for chip#%d at "
847235537Sgber			    "ctrl#%d",
848235537Sgber			    chips[chipcnt].num,
849235537Sgber			    chips[chipcnt].ctrl_num);
850235537Sgber			return (EINVAL);
851235537Sgber		}
852235537Sgber
853235537Sgber		if ((chips[chipcnt].prog_time < DELAYTIME_MIN ||
854235537Sgber		    chips[chipcnt].prog_time > DELAYTIME_MAX) &&
855235537Sgber		    chips[chipcnt].prog_time != 0) {
856235537Sgber			error("Invalid prog time value for chip#%d at "
857235537Sgber			    "ctr#%d!",
858235537Sgber			    chips[chipcnt].num,
859235537Sgber			    chips[chipcnt].ctrl_num);
860235537Sgber			return (EINVAL);
861235537Sgber		}
862235537Sgber
863235537Sgber		if ((chips[chipcnt].read_time < DELAYTIME_MIN ||
864235537Sgber		    chips[chipcnt].read_time > DELAYTIME_MAX) &&
865235537Sgber		    chips[chipcnt].read_time != 0) {
866235537Sgber			error("Invalid read time value for chip#%d at "
867235537Sgber			    "ctrl#%d!",
868235537Sgber			    chips[chipcnt].num,
869235537Sgber			    chips[chipcnt].ctrl_num);
870235537Sgber			return (EINVAL);
871235537Sgber		}
872235537Sgber	}
873235537Sgber	/* Check if chips attached to the same controller, have same width */
874235537Sgber	for (i = 0; i < ctrlcnt; i++) {
875235537Sgber		width = -1;
876235537Sgber		for (j = 0; j < cchipcnt; j++) {
877235537Sgber			if (chips[j].ctrl_num == i) {
878235537Sgber				if (width == -1) {
879235537Sgber					width = chips[j].width;
880235537Sgber				} else {
881235537Sgber					if (width != chips[j].width) {
882235537Sgber						error("Chips attached to "
883235537Sgber						    "ctrl#%d have different "
884235537Sgber						    "widths!\n", i);
885235537Sgber						return (EINVAL);
886235537Sgber					}
887235537Sgber				}
888235537Sgber			}
889235537Sgber		}
890235537Sgber	}
891235537Sgber
892235537Sgber	return (0);
893235537Sgber}
894235537Sgber
895235537Sgberstatic uint8_t
896235537Sgbervalidate_ctrls(struct sim_ctrl *ctrl, int ctrlcnt)
897235537Sgber{
898235537Sgber	for (ctrlcnt -= 1; ctrlcnt >= 0; ctrlcnt--) {
899235537Sgber		if (ctrl[ctrlcnt].num > MAX_SIM_DEV) {
900235537Sgber			error("Controller no. too high (%d)!!\n",
901235537Sgber			    ctrl[ctrlcnt].num);
902235537Sgber			return (EINVAL);
903235537Sgber		}
904235537Sgber		if (ctrl[ctrlcnt].num_cs > MAX_CTRL_CS) {
905235537Sgber			error("Too many CS (%d)!!\n", ctrl[ctrlcnt].num_cs);
906235537Sgber			return (EINVAL);
907235537Sgber		}
908235537Sgber		if (ctrl[ctrlcnt].ecc != 0 && ctrl[ctrlcnt].ecc != 1) {
909235537Sgber			error("ECC is set to neither 0 nor 1 !\n");
910235537Sgber			return (EINVAL);
911235537Sgber		}
912235537Sgber	}
913235537Sgber
914235537Sgber	return (0);
915235537Sgber}
916235537Sgber
917235537Sgberstatic int validate_section_config(struct rcfile *f, const char *sect_name,
918235537Sgber    int sectno)
919235537Sgber{
920235537Sgber	struct nandsim_key *key;
921235537Sgber	struct nandsim_section *sect;
922235537Sgber	char **keys_tbl;
923235537Sgber	int i, match;
924235537Sgber
925235537Sgber	for (match = 0, sect = (struct nandsim_section *)&sections;
926235537Sgber	    sect != NULL; sect++) {
927235537Sgber		if (strcmp(sect->name, sect_name) == 0) {
928235537Sgber			match = 1;
929235537Sgber			break;
930235537Sgber		}
931235537Sgber	}
932235537Sgber
933235537Sgber	if (match == 0)
934235537Sgber		return (EINVAL);
935235537Sgber
936235537Sgber	keys_tbl = rc_getkeys(f, sect_name, sectno);
937235537Sgber	if (keys_tbl == NULL)
938235537Sgber		return (ENOMEM);
939235537Sgber
940235537Sgber	for (i = 0; keys_tbl[i] != NULL; i++) {
941235537Sgber		key = sect->keys;
942235537Sgber		match = 0;
943235537Sgber		do {
944235537Sgber			if (strcmp(keys_tbl[i], key->keyname) == 0) {
945235537Sgber				match = 1;
946235537Sgber				break;
947235537Sgber			}
948235537Sgber		} while ((++key)->keyname != NULL);
949235537Sgber
950235537Sgber		if (match == 0) {
951235537Sgber			error("Invalid key in config file: %s\n", keys_tbl[i]);
952235537Sgber			free(keys_tbl);
953235537Sgber			return (EINVAL);
954235537Sgber		}
955235537Sgber	}
956235537Sgber
957235537Sgber	free(keys_tbl);
958235537Sgber	return (0);
959235537Sgber}
960