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