]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/nandsim/nandsim_cfgparse.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / nandsim / nandsim_cfgparse.c
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$");
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
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
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
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
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
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
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 overriden.
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
381 destroy_ctrls(struct sim_ctrl *ctrls)
382 {
383
384         free(ctrls);
385 }
386
387 static int
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 overriden.
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
453 destroy_chips(struct sim_chip *chips)
454 {
455
456         free(chips);
457 }
458
459 int
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
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
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
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
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
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
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
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
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 }