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