Deleted Added
full compact
nandsim_cfgparse.c (249744) nandsim_cfgparse.c (289677)
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>
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: head/usr.sbin/nandsim/nandsim_cfgparse.c 249744 2013-04-21 22:47:24Z ed $");
28__FBSDID("$FreeBSD: head/usr.sbin/nandsim/nandsim_cfgparse.c 289677 2015-10-21 05:37:09Z eadler $");
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. */
76static struct sim_ctrl ctrl_conf;
77/* Structure holding configuration for chip. */
78static struct sim_chip chip_conf;
79
80static 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
94static 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
133static 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
139static uint8_t logoutputtoint(char *, int *);
140static uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int);
141static uint8_t validate_ctrls(struct sim_ctrl *, int);
142static int configure_sim(const char *, struct rcfile *);
143static int create_ctrls(struct rcfile *, struct sim_ctrl **, int *);
144static int create_chips(struct rcfile *, struct sim_chip **, int *);
145static void destroy_ctrls(struct sim_ctrl *);
146static void destroy_chips(struct sim_chip *);
147static int validate_section_config(struct rcfile *, const char *, int);
148
149int
150convert_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
165int
166convert_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. */
182int
183parse_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 }
246out:
247 free(origstr);
248 return (count);
249}
250
251/* Convert logoutput strings literals into appropriate ints. */
252static uint8_t
253logoutputtoint(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
279static int
280configure_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
325static int
326create_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
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. */
76static struct sim_ctrl ctrl_conf;
77/* Structure holding configuration for chip. */
78static struct sim_chip chip_conf;
79
80static 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
94static 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
133static 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
139static uint8_t logoutputtoint(char *, int *);
140static uint8_t validate_chips(struct sim_chip *, int, struct sim_ctrl *, int);
141static uint8_t validate_ctrls(struct sim_ctrl *, int);
142static int configure_sim(const char *, struct rcfile *);
143static int create_ctrls(struct rcfile *, struct sim_ctrl **, int *);
144static int create_chips(struct rcfile *, struct sim_chip **, int *);
145static void destroy_ctrls(struct sim_ctrl *);
146static void destroy_chips(struct sim_chip *);
147static int validate_section_config(struct rcfile *, const char *, int);
148
149int
150convert_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
165int
166convert_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. */
182int
183parse_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 }
246out:
247 free(origstr);
248 return (count);
249}
250
251/* Convert logoutput strings literals into appropriate ints. */
252static uint8_t
253logoutputtoint(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
279static int
280configure_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
325static int
326create_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.
352 * defined in config file, values will be overridden.
353 */
354 memset((void *)&ctrl_conf.ecc_layout, 0xff,
355 sizeof(ctrl_conf.ecc_layout));
356
357 if (validate_section_config(f, "ctrl", i) != 0) {
358 free(ctrlsptr);
359 return (EINVAL);
360 }
361
362 if (parse_section(f, "ctrl", i) != 0) {
363 free(ctrlsptr);
364 return (EINVAL);
365 }
366
367 memcpy(&ctrlsptr[i], &ctrl_conf, sizeof(ctrl_conf));
368 /* Try to create ctrl with config parsed */
369 debug("NUM=%d\nNUM_CS=%d\nECC=%d\nFILENAME=%s\nECC_LAYOUT[0]"
370 "=%d\nECC_LAYOUT[1]=%d\n\n",
371 ctrlsptr[i].num, ctrlsptr[i].num_cs, ctrlsptr[i].ecc,
372 ctrlsptr[i].filename, ctrlsptr[i].ecc_layout[0],
373 ctrlsptr[i].ecc_layout[1]);
374 }
375 *cnt = count;
376 *ctrls = ctrlsptr;
377 return (0);
378}
379
380static void
381destroy_ctrls(struct sim_ctrl *ctrls)
382{
383
384 free(ctrls);
385}
386
387static int
388create_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
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
380static void
381destroy_ctrls(struct sim_ctrl *ctrls)
382{
383
384 free(ctrls);
385}
386
387static int
388create_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.
414 * defined in config file, values will be overridden.
415 */
416 memset((void *)&chip_conf.bad_block_map, 0xff,
417 sizeof(chip_conf.bad_block_map));
418
419 if (validate_section_config(f, "chip", i) != 0) {
420 free(chipsptr);
421 return (EINVAL);
422 }
423
424 if (parse_section(f, "chip", i) != 0) {
425 free(chipsptr);
426 return (EINVAL);
427 }
428
429 memcpy(&chipsptr[i], &chip_conf, sizeof(chip_conf));
430
431 /* Try to create chip with config parsed */
432 debug("CHIP:\nNUM=%d\nCTRL_NUM=%d\nDEVID=%d\nMANID=%d\n"
433 "PAGE_SZ=%d\nOOBSZ=%d\nREAD_T=%d\nDEVMODEL=%s\n"
434 "MAN=%s\nCOLADDRCYCLES=%d\nROWADDRCYCLES=%d\nCHWIDTH=%d\n"
435 "PGS/BLK=%d\nBLK/LUN=%d\nLUNS=%d\nERR_RATIO=%d\n"
436 "WEARLEVEL=%d\nISWP=%d\n\n\n\n",
437 chipsptr[i].num, chipsptr[i].ctrl_num,
438 chipsptr[i].device_id, chipsptr[i].manufact_id,
439 chipsptr[i].page_size, chipsptr[i].oob_size,
440 chipsptr[i].read_time, chipsptr[i].device_model,
441 chipsptr[i].manufacturer, chipsptr[i].col_addr_cycles,
442 chipsptr[i].row_addr_cycles, chipsptr[i].width,
443 chipsptr[i].pgs_per_blk, chipsptr[i].blks_per_lun,
444 chipsptr[i].luns, chipsptr[i].error_ratio,
445 chipsptr[i].wear_level, chipsptr[i].is_wp);
446 }
447 *cnt = count;
448 *chips = chipsptr;
449 return (0);
450}
451
452static void
453destroy_chips(struct sim_chip *chips)
454{
455
456 free(chips);
457}
458
459int
460parse_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 */
581static int
582get_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 */
624static int
625get_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 */
653static int
654get_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 */
677static int
678get_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
697int
698parse_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
761static uint8_t
762validate_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
895static uint8_t
896validate_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
917static 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}
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
452static void
453destroy_chips(struct sim_chip *chips)
454{
455
456 free(chips);
457}
458
459int
460parse_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 */
581static int
582get_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 */
624static int
625get_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 */
653static int
654get_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 */
677static int
678get_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
697int
698parse_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
761static uint8_t
762validate_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
895static uint8_t
896validate_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
917static 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}