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 */ 26235537Sgber 27235537Sgber/* 28235537Sgber * Control application for the NAND simulator. 29235537Sgber */ 30235537Sgber 31235537Sgber#include <sys/cdefs.h> 32235537Sgber__FBSDID("$FreeBSD$"); 33235537Sgber 34235537Sgber#include <sys/errno.h> 35235537Sgber#include <sys/ioctl.h> 36235537Sgber#include <sys/mman.h> 37235537Sgber#include <sys/stat.h> 38235537Sgber#include <sys/types.h> 39235537Sgber 40235537Sgber#include <dev/nand/nandsim.h> 41235537Sgber#include <dev/nand/nand_dev.h> 42235537Sgber 43235537Sgber#include <ctype.h> 44235537Sgber#include <fcntl.h> 45235537Sgber#include <getopt.h> 46235537Sgber#include <stdio.h> 47235537Sgber#include <stdlib.h> 48235537Sgber#include <string.h> 49235537Sgber#include <stdarg.h> 50235537Sgber#include <unistd.h> 51235537Sgber#include <stdlib.h> 52235537Sgber#include <limits.h> 53235537Sgber#include <sysexits.h> 54235537Sgber 55235537Sgber#include "nandsim_cfgparse.h" 56235537Sgber 57235537Sgber#define SIMDEVICE "/dev/nandsim.ioctl" 58235537Sgber 59235537Sgber#define error(fmt, args...) do { \ 60235537Sgber printf("ERROR: " fmt "\n", ##args); } while (0) 61235537Sgber 62235537Sgber#define warn(fmt, args...) do { \ 63235537Sgber printf("WARNING: " fmt "\n", ##args); } while (0) 64235537Sgber 65235537Sgber#define DEBUG 66235537Sgber#undef DEBUG 67235537Sgber 68235537Sgber#ifdef DEBUG 69235537Sgber#define debug(fmt, args...) do { \ 70235537Sgber printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0) 71235537Sgber#else 72235537Sgber#define debug(fmt, args...) do {} while(0) 73235537Sgber#endif 74235537Sgber 75235537Sgber#define NANDSIM_RAM_LOG_SIZE 16384 76235537Sgber 77235537Sgber#define MSG_NOTRUNNING "Controller#%d is not running.Please start" \ 78235537Sgber " it first." 79235537Sgber#define MSG_RUNNING "Controller#%d is already running!" 80235537Sgber#define MSG_CTRLCHIPNEEDED "You have to specify ctrl_no:cs_no pair!" 81235537Sgber#define MSG_STATUSACQCTRLCHIP "Could not acquire status for ctrl#%d chip#%d" 82235537Sgber#define MSG_STATUSACQCTRL "Could not acquire status for ctrl#%d" 83235537Sgber#define MSG_NOCHIP "There is no such chip configured (chip#%d "\ 84235537Sgber "at ctrl#%d)!" 85235537Sgber 86235537Sgber#define MSG_NOCTRL "Controller#%d is not configured!" 87235537Sgber#define MSG_NOTCONFIGDCTRLCHIP "Chip connected to ctrl#%d at cs#%d " \ 88235537Sgber "is not configured." 89235537Sgber 90235537Sgbertypedef int (commandfunc_t)(int , char **); 91235537Sgber 92235537Sgberstatic struct nandsim_command *getcommand(char *); 93235537Sgberstatic int parse_devstring(char *, int *, int *); 94235537Sgberstatic void printchip(struct sim_chip *, uint8_t); 95235537Sgberstatic void printctrl(struct sim_ctrl *); 96235537Sgberstatic int opendev(int *); 97235537Sgberstatic commandfunc_t cmdstatus; 98235537Sgberstatic commandfunc_t cmdconf; 99235537Sgberstatic commandfunc_t cmdstart; 100235537Sgberstatic commandfunc_t cmdstop; 101235537Sgberstatic commandfunc_t cmdmod; 102235537Sgberstatic commandfunc_t cmderror; 103235537Sgberstatic commandfunc_t cmdbb; 104235537Sgberstatic commandfunc_t cmdfreeze; 105235537Sgberstatic commandfunc_t cmdlog; 106235537Sgberstatic commandfunc_t cmdstats; 107235537Sgberstatic commandfunc_t cmddump; 108235537Sgberstatic commandfunc_t cmdrestore; 109235537Sgberstatic commandfunc_t cmddestroy; 110235537Sgberstatic commandfunc_t cmdhelp; 111235537Sgberstatic int checkusage(int, int, char **); 112235537Sgberstatic int is_chip_created(int, int, int *); 113235537Sgberstatic int is_ctrl_created(int, int *); 114235537Sgberstatic int is_ctrl_running(int, int *); 115235537Sgberstatic int assert_chip_connected(int , int); 116235537Sgberstatic int printstats(int, int, uint32_t, int); 117235537Sgber 118235537Sgberstruct nandsim_command { 119235537Sgber const char *cmd_name; /* Command name */ 120235537Sgber commandfunc_t *commandfunc; /* Ptr to command function */ 121235537Sgber uint8_t req_argc; /* Mandatory arguments count */ 122235537Sgber const char *usagestring; /* Usage string */ 123235537Sgber}; 124235537Sgber 125235537Sgberstatic struct nandsim_command commands[] = { 126235537Sgber {"status", cmdstatus, 1, 127235537Sgber "status <ctl_no|--all|-a> [-v]\n" }, 128235537Sgber {"conf", cmdconf, 1, 129235537Sgber "conf <filename>\n" }, 130235537Sgber {"start", cmdstart, 1, 131235537Sgber "start <ctrl_no>\n" }, 132235537Sgber {"mod", cmdmod, 2, 133235537Sgber "mod [-l <loglevel>] | <ctl_no:cs_no> [-p <prog_time>]\n" 134235537Sgber "\t[-e <erase_time>] [-r <read_time>]\n" 135235537Sgber "\t[-E <error_ratio>] | [-h]\n" }, 136235537Sgber {"stop", cmdstop, 1, 137235537Sgber "stop <ctrl_no>\n" }, 138235537Sgber {"error", cmderror, 5, 139235537Sgber "error <ctrl_no:cs_no> <page_num> <column> <length> <pattern>\n" }, 140235537Sgber {"bb", cmdbb, 2, 141235537Sgber "bb <ctl_no:cs_no> [blk_num1,blk_num2,..] [-U] [-L]\n" }, 142235537Sgber {"freeze", cmdfreeze, 1, 143235537Sgber "freeze [ctrl_no]\n" }, 144235537Sgber {"log", cmdlog, 1, 145235537Sgber "log <ctrl_no|--all|-a>\n" }, 146235537Sgber {"stats", cmdstats, 2, 147235537Sgber "stats <ctrl_no:cs_no> <pagenumber>\n" }, 148235537Sgber {"dump", cmddump, 2, 149235537Sgber "dump <ctrl_no:cs_no> <filename>\n" }, 150235537Sgber {"restore", cmdrestore, 2, 151235537Sgber "restore <ctrl_no:chip_no> <filename>\n" }, 152235537Sgber {"destroy", cmddestroy, 1, 153235537Sgber "destroy <ctrl_no[:cs_no]|--all|-a>\n" }, 154235537Sgber {"help", cmdhelp, 0, 155235537Sgber "help [-v]" }, 156235537Sgber {NULL, NULL, 0, NULL}, 157235537Sgber}; 158235537Sgber 159235537Sgber 160235537Sgber/* Parse command name, and start appropriate function */ 161235537Sgberstatic struct nandsim_command* 162235537Sgbergetcommand(char *arg) 163235537Sgber{ 164235537Sgber struct nandsim_command *opts; 165235537Sgber 166235537Sgber for (opts = commands; (opts != NULL) && 167235537Sgber (opts->cmd_name != NULL); opts++) { 168235537Sgber if (strcmp(opts->cmd_name, arg) == 0) 169235537Sgber return (opts); 170235537Sgber } 171235537Sgber return (NULL); 172235537Sgber} 173235537Sgber 174235537Sgber/* 175235537Sgber * Parse given string in format <ctrl_no>:<cs_no>, if possible -- set 176235537Sgber * ctrl and/or cs, and return 0 (success) or 1 (in case of error). 177235537Sgber * 178235537Sgber * ctrl == 0xff && chip == 0xff : '--all' flag specified 179235537Sgber * ctrl != 0xff && chip != 0xff : both ctrl & chip were specified 180235537Sgber * ctrl != 0xff && chip == 0xff : only ctrl was specified 181235537Sgber */ 182235537Sgberstatic int 183235537Sgberparse_devstring(char *str, int *ctrl, int *cs) 184235537Sgber{ 185235537Sgber char *tmpstr; 186235537Sgber unsigned int num = 0; 187235537Sgber 188235537Sgber /* Ignore white spaces at the beginning */ 189235537Sgber while (isspace(*str) && (*str != '\0')) 190235537Sgber str++; 191235537Sgber 192235537Sgber *ctrl = 0xff; 193235537Sgber *cs = 0xff; 194235537Sgber if (strcmp(str, "--all") == 0 || 195235537Sgber strcmp(str, "-a") == 0) { 196235537Sgber /* If --all or -a is specified, ctl==chip==0xff */ 197235537Sgber debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); 198235537Sgber return (0); 199235537Sgber } 200235537Sgber /* Separate token and try to convert it to int */ 201235537Sgber tmpstr = (char *)strtok(str, ":"); 202235537Sgber if ((tmpstr != NULL) && (*tmpstr != '\0')) { 203235537Sgber if (convert_arguint(tmpstr, &num) != 0) 204235537Sgber return (1); 205235537Sgber 206235537Sgber if (num > MAX_SIM_DEV - 1) { 207235537Sgber error("Invalid ctrl_no supplied: %s. Valid ctrl_no " 208235537Sgber "value must lie between 0 and 3!", tmpstr); 209235537Sgber return (1); 210235537Sgber } 211235537Sgber 212235537Sgber *ctrl = num; 213235537Sgber tmpstr = (char *)strtok(NULL, ":"); 214235537Sgber 215235537Sgber if ((tmpstr != NULL) && (*tmpstr != '\0')) { 216235537Sgber if (convert_arguint(tmpstr, &num) != 0) 217235537Sgber return (1); 218235537Sgber 219235537Sgber /* Check if chip_no is valid */ 220235537Sgber if (num > MAX_CTRL_CS - 1) { 221235537Sgber error("Invalid chip_no supplied: %s. Valid " 222235537Sgber "chip_no value must lie between 0 and 3!", 223235537Sgber tmpstr); 224235537Sgber return (1); 225235537Sgber } 226235537Sgber *cs = num; 227235537Sgber } 228235537Sgber } else 229235537Sgber /* Empty devstring supplied */ 230235537Sgber return (1); 231235537Sgber 232235537Sgber debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); 233235537Sgber return (0); 234235537Sgber} 235235537Sgber 236235537Sgberstatic int 237235537Sgberopendev(int *fd) 238235537Sgber{ 239235537Sgber 240235537Sgber *fd = open(SIMDEVICE, O_RDWR); 241235537Sgber if (*fd == -1) { 242235537Sgber error("Could not open simulator device file (%s)!", 243235537Sgber SIMDEVICE); 244235537Sgber return (EX_OSFILE); 245235537Sgber } 246235537Sgber return (EX_OK); 247235537Sgber} 248235537Sgber 249235537Sgberstatic int 250235537Sgberopencdev(int *cdevd, int ctrl, int chip) 251235537Sgber{ 252235537Sgber char fname[255]; 253235537Sgber 254235537Sgber sprintf(fname, "/dev/nandsim%d.%d", ctrl, chip); 255235537Sgber *cdevd = open(fname, O_RDWR); 256235537Sgber if (*cdevd == -1) 257235537Sgber return (EX_NOINPUT); 258235537Sgber 259235537Sgber return (EX_OK); 260235537Sgber} 261235537Sgber 262235537Sgber/* 263235537Sgber * Check if given arguments count match requirements. If no, or 264235537Sgber * --help (-h) flag is specified -- return 1 (print usage) 265235537Sgber */ 266235537Sgberstatic int 267235537Sgbercheckusage(int gargc, int argsreqd, char **gargv) 268235537Sgber{ 269235537Sgber 270235537Sgber if (gargc < argsreqd + 2 || (gargc >= (argsreqd + 2) && 271235537Sgber (strcmp(gargv[1], "--help") == 0 || 272235537Sgber strcmp(gargv[1], "-h") == 0))) 273235537Sgber return (1); 274235537Sgber 275235537Sgber return (0); 276235537Sgber} 277235537Sgber 278235537Sgberstatic int 279235537Sgbercmdstatus(int gargc, char **gargv) 280235537Sgber{ 281235537Sgber int chip = 0, ctl = 0, err = 0, fd, idx, idx2, start, stop; 282235537Sgber uint8_t verbose = 0; 283235537Sgber struct sim_ctrl ctrlconf; 284235537Sgber struct sim_chip chipconf; 285235537Sgber 286235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 287235537Sgber if (err) { 288235537Sgber return (EX_USAGE); 289235537Sgber } else if (ctl == 0xff) { 290235537Sgber /* Every controller */ 291235537Sgber start = 0; 292235537Sgber stop = MAX_SIM_DEV-1; 293235537Sgber } else { 294235537Sgber /* Specified controller only */ 295235537Sgber start = ctl; 296235537Sgber stop = ctl; 297235537Sgber } 298235537Sgber 299235537Sgber if (opendev(&fd) != EX_OK) 300235537Sgber return (EX_OSFILE); 301235537Sgber 302235537Sgber for (idx = 0; idx < gargc; idx ++) 303235537Sgber if (strcmp(gargv[idx], "-v") == 0 || 304235537Sgber strcmp(gargv[idx], "--verbose") == 0) 305235537Sgber verbose = 1; 306235537Sgber 307235537Sgber for (idx = start; idx <= stop; idx++) { 308235537Sgber ctrlconf.num = idx; 309235537Sgber err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrlconf); 310235537Sgber if (err) { 311235537Sgber err = EX_SOFTWARE; 312235537Sgber error(MSG_STATUSACQCTRL, idx); 313235537Sgber continue; 314235537Sgber } 315235537Sgber 316235537Sgber printctrl(&ctrlconf); 317235537Sgber 318235537Sgber for (idx2 = 0; idx2 < MAX_CTRL_CS; idx2++) { 319235537Sgber chipconf.num = idx2; 320235537Sgber chipconf.ctrl_num = idx; 321235537Sgber 322235537Sgber err = ioctl(fd, NANDSIM_STATUS_CHIP, &chipconf); 323235537Sgber if (err) { 324235537Sgber err = EX_SOFTWARE; 325235537Sgber error(MSG_STATUSACQCTRL, idx); 326235537Sgber continue; 327235537Sgber } 328235537Sgber 329235537Sgber printchip(&chipconf, verbose); 330235537Sgber } 331235537Sgber } 332235537Sgber close(fd); 333235537Sgber return (err); 334235537Sgber} 335235537Sgber 336235537Sgberstatic int 337235537Sgbercmdconf(int gargc __unused, char **gargv) 338235537Sgber{ 339235537Sgber int err; 340235537Sgber 341235537Sgber err = parse_config(gargv[2], SIMDEVICE); 342235537Sgber if (err) 343235537Sgber return (EX_DATAERR); 344235537Sgber 345235537Sgber return (EX_OK); 346235537Sgber} 347235537Sgber 348235537Sgberstatic int 349235537Sgbercmdstart(int gargc __unused, char **gargv) 350235537Sgber{ 351235537Sgber int chip = 0, ctl = 0, err = 0, fd, running, state; 352235537Sgber 353235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 354235537Sgber if (err) 355235537Sgber return (EX_USAGE); 356235537Sgber 357235537Sgber err = is_ctrl_created(ctl, &state); 358235537Sgber if (err) { 359235537Sgber return (EX_SOFTWARE); 360235537Sgber } else if (state == 0) { 361235537Sgber error(MSG_NOCTRL, ctl); 362235537Sgber return (EX_SOFTWARE); 363235537Sgber } 364235537Sgber 365235537Sgber err = is_ctrl_running(ctl, &running); 366235537Sgber if (err) 367235537Sgber return (EX_SOFTWARE); 368235537Sgber 369235537Sgber if (running) { 370235537Sgber warn(MSG_RUNNING, ctl); 371235537Sgber } else { 372235537Sgber if (opendev(&fd) != EX_OK) 373235537Sgber return (EX_OSFILE); 374235537Sgber 375235537Sgber err = ioctl(fd, NANDSIM_START_CTRL, &ctl); 376235537Sgber close(fd); 377235537Sgber if (err) { 378235537Sgber error("Cannot start controller#%d", ctl); 379235537Sgber err = EX_SOFTWARE; 380235537Sgber } 381235537Sgber } 382235537Sgber return (err); 383235537Sgber} 384235537Sgber 385235537Sgberstatic int 386235537Sgbercmdstop(int gargc __unused, char **gargv) 387235537Sgber{ 388235537Sgber int chip = 0, ctl = 0, err = 0, fd, running; 389235537Sgber 390235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 391235537Sgber if (err) 392235537Sgber return (EX_USAGE); 393235537Sgber 394235537Sgber err = is_ctrl_running(ctl, &running); 395235537Sgber if (err) 396235537Sgber return (EX_SOFTWARE); 397235537Sgber 398235537Sgber if (!running) { 399235537Sgber error(MSG_NOTRUNNING, ctl); 400235537Sgber } else { 401235537Sgber if (opendev(&fd) != EX_OK) 402235537Sgber return (EX_OSFILE); 403235537Sgber 404235537Sgber err = ioctl(fd, NANDSIM_STOP_CTRL, &ctl); 405235537Sgber close(fd); 406235537Sgber if (err) { 407235537Sgber error("Cannot stop controller#%d", ctl); 408235537Sgber err = EX_SOFTWARE; 409235537Sgber } 410235537Sgber } 411235537Sgber 412235537Sgber return (err); 413235537Sgber} 414235537Sgber 415235537Sgberstatic int 416235537Sgbercmdmod(int gargc __unused, char **gargv) 417235537Sgber{ 418235537Sgber int chip, ctl, err = 0, fd = -1, i; 419235537Sgber struct sim_mod mods; 420235537Sgber 421235537Sgber if (gargc >= 4) { 422235537Sgber if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2], 423235537Sgber "-l") == 0) { 424293290Sbdrewery /* Set loglevel (ctrl:chip pair independent) */ 425235537Sgber mods.field = SIM_MOD_LOG_LEVEL; 426235537Sgber 427235537Sgber if (convert_arguint(gargv[3], &mods.new_value) != 0) 428235537Sgber return (EX_SOFTWARE); 429235537Sgber 430235537Sgber if (opendev(&fd) != EX_OK) 431235537Sgber return (EX_OSFILE); 432235537Sgber 433235537Sgber err = ioctl(fd, NANDSIM_MODIFY, &mods); 434235537Sgber if (err) { 435235537Sgber error("simulator parameter %s could not be " 436235537Sgber "modified !", gargv[3]); 437235537Sgber close(fd); 438235537Sgber return (EX_SOFTWARE); 439235537Sgber } 440235537Sgber 441235537Sgber debug("request : loglevel = %d\n", mods.new_value); 442235537Sgber close(fd); 443235537Sgber return (EX_OK); 444235537Sgber } 445235537Sgber } 446235537Sgber 447235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 448235537Sgber if (err) 449235537Sgber return (EX_USAGE); 450235537Sgber 451235537Sgber else if (chip == 0xff) { 452235537Sgber error(MSG_CTRLCHIPNEEDED); 453235537Sgber return (EX_USAGE); 454235537Sgber } 455235537Sgber 456235537Sgber if (!assert_chip_connected(ctl, chip)) 457235537Sgber return (EX_SOFTWARE); 458235537Sgber 459235537Sgber if (opendev(&fd) != EX_OK) 460235537Sgber return (EX_OSFILE); 461235537Sgber 462235537Sgber /* Find out which flags were passed */ 463235537Sgber for (i = 3; i < gargc; i++) { 464235537Sgber 465235537Sgber if (convert_arguint(gargv[i + 1], &mods.new_value) != 0) 466235537Sgber continue; 467235537Sgber 468235537Sgber if (strcmp(gargv[i], "--prog-time") == 0 || 469235537Sgber strcmp(gargv[i], "-p") == 0) { 470235537Sgber 471235537Sgber mods.field = SIM_MOD_PROG_TIME; 472235537Sgber debug("request : progtime = %d\n", mods.new_value); 473235537Sgber 474235537Sgber } else if (strcmp(gargv[i], "--erase-time") == 0 || 475235537Sgber strcmp(gargv[i], "-e") == 0) { 476235537Sgber 477235537Sgber mods.field = SIM_MOD_ERASE_TIME; 478235537Sgber debug("request : eraseime = %d\n", mods.new_value); 479235537Sgber 480235537Sgber } else if (strcmp(gargv[i], "--read-time") == 0 || 481235537Sgber strcmp(gargv[i], "-r") == 0) { 482235537Sgber 483235537Sgber mods.field = SIM_MOD_READ_TIME; 484235537Sgber debug("request : read_time = %d\n", mods.new_value); 485235537Sgber 486235537Sgber } else if (strcmp(gargv[i], "--error-ratio") == 0 || 487235537Sgber strcmp(gargv[i], "-E") == 0) { 488235537Sgber 489235537Sgber mods.field = SIM_MOD_ERROR_RATIO; 490235537Sgber debug("request : error_ratio = %d\n", mods.new_value); 491235537Sgber 492235537Sgber } else { 493235537Sgber /* Flag not recognized, or nothing specified. */ 494235537Sgber error("Unrecognized flag:%s\n", gargv[i]); 495235537Sgber if (fd >= 0) 496235537Sgber close(fd); 497235537Sgber return (EX_USAGE); 498235537Sgber } 499235537Sgber 500235537Sgber mods.chip_num = chip; 501235537Sgber mods.ctrl_num = ctl; 502235537Sgber 503235537Sgber /* Call appropriate ioctl */ 504235537Sgber err = ioctl(fd, NANDSIM_MODIFY, &mods); 505235537Sgber if (err) { 506235537Sgber error("simulator parameter %s could not be modified! ", 507235537Sgber gargv[i]); 508235537Sgber continue; 509235537Sgber } 510235537Sgber i++; 511235537Sgber } 512235537Sgber close(fd); 513235537Sgber return (EX_OK); 514235537Sgber} 515235537Sgber 516235537Sgberstatic int 517235537Sgbercmderror(int gargc __unused, char **gargv) 518235537Sgber{ 519235537Sgber uint32_t page, column, len, pattern; 520235537Sgber int chip = 0, ctl = 0, err = 0, fd; 521235537Sgber struct sim_error sim_err; 522235537Sgber 523235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 524235537Sgber if (err) 525235537Sgber return (EX_USAGE); 526235537Sgber 527235537Sgber if (chip == 0xff) { 528235537Sgber error(MSG_CTRLCHIPNEEDED); 529235537Sgber return (EX_USAGE); 530235537Sgber } 531235537Sgber 532235537Sgber if (convert_arguint(gargv[3], &page) || 533235537Sgber convert_arguint(gargv[4], &column) || 534235537Sgber convert_arguint(gargv[5], &len) || 535235537Sgber convert_arguint(gargv[6], &pattern)) 536235537Sgber return (EX_SOFTWARE); 537235537Sgber 538235537Sgber if (!assert_chip_connected(ctl, chip)) 539235537Sgber return (EX_SOFTWARE); 540235537Sgber 541235537Sgber sim_err.page_num = page; 542235537Sgber sim_err.column = column; 543235537Sgber sim_err.len = len; 544235537Sgber sim_err.pattern = pattern; 545235537Sgber sim_err.ctrl_num = ctl; 546235537Sgber sim_err.chip_num = chip; 547235537Sgber 548235537Sgber if (opendev(&fd) != EX_OK) 549235537Sgber return (EX_OSFILE); 550235537Sgber 551235537Sgber err = ioctl(fd, NANDSIM_INJECT_ERROR, &sim_err); 552235537Sgber 553235537Sgber close(fd); 554235537Sgber if (err) { 555235537Sgber error("Could not inject error !"); 556235537Sgber return (EX_SOFTWARE); 557235537Sgber } 558235537Sgber return (EX_OK); 559235537Sgber} 560235537Sgber 561235537Sgberstatic int 562235537Sgbercmdbb(int gargc, char **gargv) 563235537Sgber{ 564235537Sgber struct sim_block_state bs; 565235537Sgber struct chip_param_io cparams; 566235537Sgber uint32_t blkidx; 567235537Sgber int c, cdevd, chip = 0, ctl = 0, err = 0, fd, idx; 568235537Sgber uint8_t flagL = 0, flagU = 0; 569235537Sgber int *badblocks = NULL; 570235537Sgber 571235537Sgber /* Check for --list/-L or --unmark/-U flags */ 572235537Sgber for (idx = 3; idx < gargc; idx++) { 573235537Sgber if (strcmp(gargv[idx], "--list") == 0 || 574235537Sgber strcmp(gargv[idx], "-L") == 0) 575235537Sgber flagL = idx; 576235537Sgber if (strcmp(gargv[idx], "--unmark") == 0 || 577235537Sgber strcmp(gargv[idx], "-U") == 0) 578235537Sgber flagU = idx; 579235537Sgber } 580235537Sgber 581235537Sgber if (flagL == 2 || flagU == 2 || flagU == 3) 582235537Sgber return (EX_USAGE); 583235537Sgber 584235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 585235537Sgber if (err) { 586235537Sgber return (EX_USAGE); 587235537Sgber } 588235537Sgber if (chip == 0xff || ctl == 0xff) { 589235537Sgber error(MSG_CTRLCHIPNEEDED); 590235537Sgber return (EX_USAGE); 591235537Sgber } 592235537Sgber 593235537Sgber bs.ctrl_num = ctl; 594235537Sgber bs.chip_num = chip; 595235537Sgber 596235537Sgber if (!assert_chip_connected(ctl, chip)) 597235537Sgber return (EX_SOFTWARE); 598235537Sgber 599235537Sgber if (opencdev(&cdevd, ctl, chip) != EX_OK) 600235537Sgber return (EX_OSFILE); 601235537Sgber 602235537Sgber err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); 603235537Sgber if (err) 604235537Sgber return (EX_SOFTWARE); 605235537Sgber 606235537Sgber close(cdevd); 607235537Sgber 608235537Sgber bs.ctrl_num = ctl; 609235537Sgber bs.chip_num = chip; 610235537Sgber 611235537Sgber if (opendev(&fd) != EX_OK) 612235537Sgber return (EX_OSFILE); 613235537Sgber 614235537Sgber if (flagL != 3) { 615235537Sgber /* 616235537Sgber * Flag -L was specified either after blocklist or was not 617235537Sgber * specified at all. 618235537Sgber */ 619235537Sgber c = parse_intarray(gargv[3], &badblocks); 620235537Sgber 621235537Sgber for (idx = 0; idx < c; idx++) { 622235537Sgber bs.block_num = badblocks[idx]; 623235537Sgber /* Do not change wearout */ 624235537Sgber bs.wearout = -1; 625235537Sgber bs.state = (flagU == 0) ? NANDSIM_BAD_BLOCK : 626235537Sgber NANDSIM_GOOD_BLOCK; 627235537Sgber 628235537Sgber err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); 629235537Sgber if (err) { 630235537Sgber error("Could not set bad block(%d) for " 631235537Sgber "controller (%d)!", 632235537Sgber badblocks[idx], ctl); 633235537Sgber err = EX_SOFTWARE; 634235537Sgber break; 635235537Sgber } 636235537Sgber } 637235537Sgber } 638235537Sgber if (flagL != 0) { 639235537Sgber /* If flag -L was specified (anywhere) */ 640235537Sgber for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 641235537Sgber bs.block_num = blkidx; 642235537Sgber /* Do not change the wearout */ 643235537Sgber bs.wearout = -1; 644235537Sgber err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); 645235537Sgber if (err) { 646235537Sgber error("Could not acquire block state"); 647235537Sgber err = EX_SOFTWARE; 648235537Sgber continue; 649235537Sgber } 650235537Sgber printf("Block#%d: wear count: %d %s\n", blkidx, 651235537Sgber bs.wearout, 652235537Sgber (bs.state == NANDSIM_BAD_BLOCK) ? "BAD":"GOOD"); 653235537Sgber } 654235537Sgber } 655235537Sgber close(fd); 656235537Sgber return (err); 657235537Sgber} 658235537Sgber 659235537Sgberstatic int 660235537Sgbercmdfreeze(int gargc __unused, char **gargv) 661235537Sgber{ 662235537Sgber int chip = 0, ctl = 0, err = 0, fd, i, start = 0, state, stop = 0; 663235537Sgber struct sim_ctrl_chip ctrlchip; 664235537Sgber 665235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 666235537Sgber if (err) 667235537Sgber return (EX_USAGE); 668235537Sgber 669235537Sgber if (ctl == 0xff) { 670235537Sgber error("You have to specify at least controller number"); 671235537Sgber return (EX_USAGE); 672235537Sgber } 673235537Sgber 674235537Sgber if (ctl != 0xff && chip == 0xff) { 675235537Sgber start = 0; 676235537Sgber stop = MAX_CTRL_CS - 1; 677235537Sgber } else { 678235537Sgber start = chip; 679235537Sgber stop = chip; 680235537Sgber } 681235537Sgber 682235537Sgber ctrlchip.ctrl_num = ctl; 683235537Sgber 684235537Sgber err = is_ctrl_running(ctl, &state); 685235537Sgber if (err) 686235537Sgber return (EX_SOFTWARE); 687235537Sgber if (state == 0) { 688235537Sgber error(MSG_NOTRUNNING, ctl); 689235537Sgber return (EX_SOFTWARE); 690235537Sgber } 691235537Sgber 692235537Sgber if (opendev(&fd) != EX_OK) 693235537Sgber return (EX_OSFILE); 694235537Sgber 695235537Sgber for (i = start; i <= stop; i++) { 696235537Sgber err = is_chip_created(ctl, i, &state); 697235537Sgber if (err) 698235537Sgber return (EX_SOFTWARE); 699235537Sgber else if (state == 0) { 700235537Sgber continue; 701235537Sgber } 702235537Sgber 703235537Sgber ctrlchip.chip_num = i; 704235537Sgber err = ioctl(fd, NANDSIM_FREEZE, &ctrlchip); 705235537Sgber if (err) { 706235537Sgber error("Could not freeze ctrl#%d chip#%d", ctl, i); 707235537Sgber close(fd); 708235537Sgber return (EX_SOFTWARE); 709235537Sgber } 710235537Sgber } 711235537Sgber close(fd); 712235537Sgber return (EX_OK); 713235537Sgber} 714235537Sgber 715235537Sgberstatic int 716235537Sgbercmdlog(int gargc __unused, char **gargv) 717235537Sgber{ 718235537Sgber struct sim_log log; 719235537Sgber int chip = 0, ctl = 0, err = 0, fd, idx, start = 0, stop = 0; 720235537Sgber char *logbuf; 721235537Sgber 722235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 723235537Sgber if (err) 724235537Sgber return (EX_USAGE); 725235537Sgber 726235537Sgber logbuf = (char *)malloc(sizeof(char) * NANDSIM_RAM_LOG_SIZE); 727235537Sgber if (logbuf == NULL) { 728235537Sgber error("Not enough memory to create log buffer"); 729235537Sgber return (EX_SOFTWARE); 730235537Sgber } 731235537Sgber 732235537Sgber memset(logbuf, 0, NANDSIM_RAM_LOG_SIZE); 733235537Sgber log.log = logbuf; 734235537Sgber log.len = NANDSIM_RAM_LOG_SIZE; 735235537Sgber 736235537Sgber if (ctl == 0xff) { 737235537Sgber start = 0; 738235537Sgber stop = MAX_SIM_DEV-1; 739235537Sgber } else { 740235537Sgber start = ctl; 741235537Sgber stop = ctl; 742235537Sgber } 743235537Sgber 744235537Sgber if (opendev(&fd) != EX_OK) { 745235537Sgber free(logbuf); 746235537Sgber return (EX_OSFILE); 747235537Sgber } 748235537Sgber 749235537Sgber /* Print logs for selected controller(s) */ 750235537Sgber for (idx = start; idx <= stop; idx++) { 751235537Sgber log.ctrl_num = idx; 752235537Sgber 753235537Sgber err = ioctl(fd, NANDSIM_PRINT_LOG, &log); 754235537Sgber if (err) { 755235537Sgber error("Could not get log for controller %d!", idx); 756235537Sgber continue; 757235537Sgber } 758235537Sgber 759235537Sgber printf("Logs for controller#%d:\n%s\n", idx, logbuf); 760235537Sgber } 761235537Sgber 762235537Sgber free(logbuf); 763235537Sgber close(fd); 764235537Sgber return (EX_OK); 765235537Sgber} 766235537Sgber 767235537Sgberstatic int 768235537Sgbercmdstats(int gargc __unused, char **gargv) 769235537Sgber{ 770235537Sgber int cdevd, chip = 0, ctl = 0, err = 0; 771235537Sgber uint32_t pageno = 0; 772235537Sgber 773235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 774235537Sgber 775235537Sgber if (err) 776235537Sgber return (EX_USAGE); 777235537Sgber 778235537Sgber if (chip == 0xff) { 779235537Sgber error(MSG_CTRLCHIPNEEDED); 780235537Sgber return (EX_USAGE); 781235537Sgber } 782235537Sgber 783235537Sgber if (convert_arguint(gargv[3], &pageno) != 0) 784235537Sgber return (EX_USAGE); 785235537Sgber 786235537Sgber if (!assert_chip_connected(ctl, chip)) 787235537Sgber return (EX_SOFTWARE); 788235537Sgber 789235537Sgber if (opencdev(&cdevd, ctl, chip) != EX_OK) 790235537Sgber return (EX_OSFILE); 791235537Sgber 792235537Sgber err = printstats(ctl, chip, pageno, cdevd); 793235537Sgber if (err) { 794235537Sgber close(cdevd); 795235537Sgber return (EX_SOFTWARE); 796235537Sgber } 797235537Sgber close(cdevd); 798235537Sgber return (EX_OK); 799235537Sgber} 800235537Sgber 801235537Sgberstatic int 802235537Sgbercmddump(int gargc __unused, char **gargv) 803235537Sgber{ 804235537Sgber struct sim_dump dump; 805235537Sgber struct sim_block_state bs; 806235537Sgber struct chip_param_io cparams; 807235537Sgber int chip = 0, ctl = 0, err = EX_OK, fd, dumpfd; 808235537Sgber uint32_t blkidx, bwritten = 0, totalwritten = 0; 809235537Sgber void *buf; 810235537Sgber 811235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 812235537Sgber if (err) 813235537Sgber return (EX_USAGE); 814235537Sgber 815235537Sgber if (chip == 0xff || ctl == 0xff) { 816235537Sgber error(MSG_CTRLCHIPNEEDED); 817235537Sgber return (EX_USAGE); 818235537Sgber } 819235537Sgber 820235537Sgber if (!assert_chip_connected(ctl, chip)) 821235537Sgber return (EX_SOFTWARE); 822235537Sgber 823235537Sgber if (opencdev(&fd, ctl, chip) != EX_OK) 824235537Sgber return (EX_OSFILE); 825235537Sgber 826235537Sgber err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); 827235537Sgber if (err) { 828235537Sgber error("Cannot get parameters for chip %d:%d", ctl, chip); 829235537Sgber close(fd); 830235537Sgber return (EX_SOFTWARE); 831235537Sgber } 832235537Sgber close(fd); 833235537Sgber 834235537Sgber dump.ctrl_num = ctl; 835235537Sgber dump.chip_num = chip; 836235537Sgber 837235537Sgber dump.len = cparams.pages_per_block * (cparams.page_size + 838235537Sgber cparams.oob_size); 839235537Sgber 840235537Sgber buf = malloc(dump.len); 841235537Sgber if (buf == NULL) { 842235537Sgber error("Could not allocate memory!"); 843235537Sgber return (EX_SOFTWARE); 844235537Sgber } 845235537Sgber dump.data = buf; 846235537Sgber 847235537Sgber errno = 0; 848235537Sgber dumpfd = open(gargv[3], O_WRONLY | O_CREAT, 0666); 849235537Sgber if (dumpfd == -1) { 850235537Sgber error("Cannot create dump file."); 851235537Sgber free(buf); 852235537Sgber return (EX_SOFTWARE); 853235537Sgber } 854235537Sgber 855235537Sgber if (opendev(&fd)) { 856235537Sgber close(dumpfd); 857235537Sgber free(buf); 858235537Sgber return (EX_SOFTWARE); 859235537Sgber } 860235537Sgber 861235537Sgber bs.ctrl_num = ctl; 862235537Sgber bs.chip_num = chip; 863235537Sgber 864235537Sgber /* First uint32_t in file shall contain block count */ 865235537Sgber if (write(dumpfd, &cparams, sizeof(cparams)) < (int)sizeof(cparams)) { 866235537Sgber error("Error writing to dumpfile!"); 867235537Sgber close(fd); 868235537Sgber close(dumpfd); 869235537Sgber free(buf); 870235537Sgber return (EX_SOFTWARE); 871235537Sgber } 872235537Sgber 873235537Sgber /* 874235537Sgber * First loop acquires blocks states and writes them to 875235537Sgber * the dump file. 876235537Sgber */ 877235537Sgber for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 878235537Sgber bs.block_num = blkidx; 879235537Sgber err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); 880235537Sgber if (err) { 881235537Sgber error("Could not get bad block(%d) for " 882235537Sgber "controller (%d)!", blkidx, ctl); 883235537Sgber close(fd); 884235537Sgber close(dumpfd); 885235537Sgber free(buf); 886235537Sgber return (EX_SOFTWARE); 887235537Sgber } 888235537Sgber 889235537Sgber bwritten = write(dumpfd, &bs, sizeof(bs)); 890235537Sgber if (bwritten != sizeof(bs)) { 891235537Sgber error("Error writing to dumpfile"); 892235537Sgber close(fd); 893235537Sgber close(dumpfd); 894235537Sgber free(buf); 895235537Sgber return (EX_SOFTWARE); 896235537Sgber } 897235537Sgber } 898235537Sgber 899235537Sgber /* Second loop dumps the data */ 900235537Sgber for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 901235537Sgber debug("Block#%d...", blkidx); 902235537Sgber dump.block_num = blkidx; 903235537Sgber 904235537Sgber err = ioctl(fd, NANDSIM_DUMP, &dump); 905235537Sgber if (err) { 906235537Sgber error("Could not dump ctrl#%d chip#%d " 907235537Sgber "block#%d", ctl, chip, blkidx); 908235537Sgber err = EX_SOFTWARE; 909235537Sgber break; 910235537Sgber } 911235537Sgber 912235537Sgber bwritten = write(dumpfd, dump.data, dump.len); 913235537Sgber if (bwritten != dump.len) { 914235537Sgber error("Error writing to dumpfile"); 915235537Sgber err = EX_SOFTWARE; 916235537Sgber break; 917235537Sgber } 918235537Sgber debug("OK!\n"); 919235537Sgber totalwritten += bwritten; 920235537Sgber } 921235537Sgber printf("%d out of %d B written.\n", totalwritten, dump.len * blkidx); 922235537Sgber 923235537Sgber close(fd); 924235537Sgber close(dumpfd); 925235537Sgber free(buf); 926235537Sgber return (err); 927235537Sgber} 928235537Sgber 929235537Sgberstatic int 930235537Sgbercmdrestore(int gargc __unused, char **gargv) 931235537Sgber{ 932235537Sgber struct sim_dump dump; 933235537Sgber struct sim_block_state bs; 934235537Sgber struct stat filestat; 935235537Sgber int chip = 0, ctl = 0, err = 0, fd, dumpfd = -1; 936235537Sgber uint32_t blkidx, blksz, fsize = 0, expfilesz; 937235537Sgber void *buf; 938235537Sgber struct chip_param_io cparams, dumpcparams; 939235537Sgber 940235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 941235537Sgber if (err) 942235537Sgber return (EX_USAGE); 943235537Sgber else if (ctl == 0xff) { 944235537Sgber error(MSG_CTRLCHIPNEEDED); 945235537Sgber return (EX_USAGE); 946235537Sgber } 947235537Sgber 948235537Sgber if (!assert_chip_connected(ctl, chip)) 949235537Sgber return (EX_SOFTWARE); 950235537Sgber 951235537Sgber /* Get chip geometry */ 952235537Sgber if (opencdev(&fd, ctl, chip) != EX_OK) 953235537Sgber return (EX_OSFILE); 954235537Sgber 955235537Sgber err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); 956235537Sgber if (err) { 957235537Sgber error("Cannot get parameters for chip %d:%d", ctl, chip); 958235537Sgber close(fd); 959235537Sgber return (err); 960235537Sgber } 961235537Sgber close(fd); 962235537Sgber 963235537Sgber /* Obtain dump file size */ 964235537Sgber errno = 0; 965235537Sgber if (stat(gargv[3], &filestat) != 0) { 966235537Sgber error("Could not acquire file size! : %s", 967235537Sgber strerror(errno)); 968235537Sgber return (EX_IOERR); 969235537Sgber } 970235537Sgber 971235537Sgber fsize = filestat.st_size; 972235537Sgber blksz = cparams.pages_per_block * (cparams.page_size + 973235537Sgber cparams.oob_size); 974235537Sgber 975235537Sgber /* Expected dump file size for chip */ 976235537Sgber expfilesz = cparams.blocks * (blksz + sizeof(bs)) + sizeof(cparams); 977235537Sgber 978235537Sgber if (fsize != expfilesz) { 979235537Sgber error("File size does not match chip geometry (file size: %d" 980235537Sgber ", dump size: %d)", fsize, expfilesz); 981235537Sgber return (EX_SOFTWARE); 982235537Sgber } 983235537Sgber 984235537Sgber dumpfd = open(gargv[3], O_RDONLY); 985235537Sgber if (dumpfd == -1) { 986235537Sgber error("Could not open dump file!"); 987235537Sgber return (EX_IOERR); 988235537Sgber } 989235537Sgber 990235537Sgber /* Read chip params saved in dumpfile */ 991235537Sgber read(dumpfd, &dumpcparams, sizeof(dumpcparams)); 992235537Sgber 993235537Sgber /* XXX */ 994235537Sgber if (bcmp(&dumpcparams, &cparams, sizeof(cparams)) != 0) { 995235537Sgber error("Supplied dump is created for a chip with different " 996235537Sgber "chip configuration!"); 997235537Sgber close(dumpfd); 998235537Sgber return (EX_SOFTWARE); 999235537Sgber } 1000235537Sgber 1001235537Sgber if (opendev(&fd) != EX_OK) { 1002235537Sgber close(dumpfd); 1003235537Sgber return (EX_OSFILE); 1004235537Sgber } 1005235537Sgber 1006235537Sgber buf = malloc(blksz); 1007235537Sgber if (buf == NULL) { 1008235537Sgber error("Could not allocate memory for block buffer"); 1009235537Sgber close(dumpfd); 1010235537Sgber close(fd); 1011235537Sgber return (EX_SOFTWARE); 1012235537Sgber } 1013235537Sgber 1014235537Sgber dump.ctrl_num = ctl; 1015235537Sgber dump.chip_num = chip; 1016235537Sgber dump.data = buf; 1017235537Sgber /* Restore block states and wearouts */ 1018235537Sgber for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 1019235537Sgber dump.block_num = blkidx; 1020235537Sgber if (read(dumpfd, &bs, sizeof(bs)) != sizeof(bs)) { 1021235537Sgber error("Error reading dumpfile"); 1022235537Sgber close(dumpfd); 1023235537Sgber close(fd); 1024235537Sgber free(buf); 1025235537Sgber return (EX_SOFTWARE); 1026235537Sgber } 1027235537Sgber bs.ctrl_num = ctl; 1028235537Sgber bs.chip_num = chip; 1029235537Sgber debug("BLKIDX=%d BLOCKS=%d CTRL=%d CHIP=%d STATE=%d\n" 1030235537Sgber "WEAROUT=%d BS.CTRL_NUM=%d BS.CHIP_NUM=%d\n", 1031235537Sgber blkidx, cparams.blocks, dump.ctrl_num, dump.chip_num, 1032235537Sgber bs.state, bs.wearout, bs.ctrl_num, bs.chip_num); 1033235537Sgber 1034235537Sgber err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); 1035235537Sgber if (err) { 1036235537Sgber error("Could not set bad block(%d) for " 1037235537Sgber "controller: %d, chip: %d!", blkidx, ctl, chip); 1038235537Sgber close(dumpfd); 1039235537Sgber close(fd); 1040235537Sgber free(buf); 1041235537Sgber return (EX_SOFTWARE); 1042235537Sgber } 1043235537Sgber } 1044235537Sgber /* Restore data */ 1045235537Sgber for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 1046235537Sgber errno = 0; 1047235537Sgber dump.len = read(dumpfd, buf, blksz); 1048235537Sgber if (errno) { 1049235537Sgber error("Failed to read block#%d from dumpfile.", blkidx); 1050235537Sgber err = EX_SOFTWARE; 1051235537Sgber break; 1052235537Sgber } 1053235537Sgber dump.block_num = blkidx; 1054235537Sgber err = ioctl(fd, NANDSIM_RESTORE, &dump); 1055235537Sgber if (err) { 1056235537Sgber error("Could not restore block#%d of ctrl#%d chip#%d" 1057235537Sgber ": %s", blkidx, ctl, chip, strerror(errno)); 1058235537Sgber err = EX_SOFTWARE; 1059235537Sgber break; 1060235537Sgber } 1061235537Sgber } 1062235537Sgber 1063235537Sgber free(buf); 1064235537Sgber close(dumpfd); 1065235537Sgber close(fd); 1066235537Sgber return (err); 1067235537Sgber 1068235537Sgber} 1069235537Sgber 1070235537Sgberstatic int 1071235537Sgbercmddestroy(int gargc __unused, char **gargv) 1072235537Sgber{ 1073235537Sgber int chip = 0, ctl = 0, err = 0, fd, idx, idx2, state; 1074235537Sgber int chipstart, chipstop, ctrlstart, ctrlstop; 1075235537Sgber struct sim_chip_destroy chip_destroy; 1076235537Sgber 1077235537Sgber err = parse_devstring(gargv[2], &ctl, &chip); 1078235537Sgber 1079235537Sgber if (err) 1080235537Sgber return (EX_USAGE); 1081235537Sgber 1082235537Sgber if (ctl == 0xff) { 1083235537Sgber /* Every chip at every controller */ 1084235537Sgber ctrlstart = chipstart = 0; 1085235537Sgber ctrlstop = MAX_SIM_DEV - 1; 1086235537Sgber chipstop = MAX_CTRL_CS - 1; 1087235537Sgber } else { 1088235537Sgber ctrlstart = ctrlstop = ctl; 1089235537Sgber if (chip == 0xff) { 1090235537Sgber /* Every chip at selected controller */ 1091235537Sgber chipstart = 0; 1092235537Sgber chipstop = MAX_CTRL_CS - 1; 1093235537Sgber } else 1094235537Sgber /* Selected chip at selected controller */ 1095235537Sgber chipstart = chipstop = chip; 1096235537Sgber } 1097235537Sgber debug("CTRLSTART=%d CTRLSTOP=%d CHIPSTART=%d CHIPSTOP=%d\n", 1098235537Sgber ctrlstart, ctrlstop, chipstart, chipstop); 1099235537Sgber for (idx = ctrlstart; idx <= ctrlstop; idx++) { 1100235537Sgber err = is_ctrl_created(idx, &state); 1101235537Sgber if (err) { 1102235537Sgber error("Could not acquire ctrl#%d state. Cannot " 1103235537Sgber "destroy controller.", idx); 1104235537Sgber return (EX_SOFTWARE); 1105235537Sgber } 1106235537Sgber if (state == 0) { 1107235537Sgber continue; 1108235537Sgber } 1109235537Sgber err = is_ctrl_running(idx, &state); 1110235537Sgber if (err) { 1111235537Sgber error(MSG_STATUSACQCTRL, idx); 1112235537Sgber return (EX_SOFTWARE); 1113235537Sgber } 1114235537Sgber if (state != 0) { 1115235537Sgber error(MSG_RUNNING, ctl); 1116235537Sgber return (EX_SOFTWARE); 1117235537Sgber } 1118235537Sgber if (opendev(&fd) != EX_OK) 1119235537Sgber return (EX_OSFILE); 1120235537Sgber 1121235537Sgber for (idx2 = chipstart; idx2 <= chipstop; idx2++) { 1122235537Sgber err = is_chip_created(idx, idx2, &state); 1123235537Sgber if (err) { 1124235537Sgber error(MSG_STATUSACQCTRLCHIP, idx2, idx); 1125235537Sgber continue; 1126235537Sgber } 1127235537Sgber if (state == 0) 1128235537Sgber /* There is no such chip running */ 1129235537Sgber continue; 1130235537Sgber chip_destroy.ctrl_num = idx; 1131235537Sgber chip_destroy.chip_num = idx2; 1132235537Sgber ioctl(fd, NANDSIM_DESTROY_CHIP, 1133235537Sgber &chip_destroy); 1134235537Sgber } 1135235537Sgber /* If chip isn't explicitly specified -- destroy ctrl */ 1136235537Sgber if (chip == 0xff) { 1137235537Sgber err = ioctl(fd, NANDSIM_DESTROY_CTRL, &idx); 1138235537Sgber if (err) { 1139235537Sgber error("Could not destroy ctrl#%d", idx); 1140235537Sgber continue; 1141235537Sgber } 1142235537Sgber } 1143235537Sgber close(fd); 1144235537Sgber } 1145235537Sgber return (err); 1146235537Sgber} 1147235537Sgber 1148235537Sgberint 1149235537Sgbermain(int argc, char **argv) 1150235537Sgber{ 1151235537Sgber struct nandsim_command *cmdopts; 1152235537Sgber int retcode = 0; 1153235537Sgber 1154235537Sgber if (argc < 2) { 1155235537Sgber cmdhelp(argc, argv); 1156235537Sgber retcode = EX_USAGE; 1157235537Sgber } else { 1158235537Sgber cmdopts = getcommand(argv[1]); 1159235537Sgber if (cmdopts != NULL && cmdopts->commandfunc != NULL) { 1160235537Sgber if (checkusage(argc, cmdopts->req_argc, argv) == 1) { 1161235537Sgber /* Print command specific usage */ 1162235537Sgber printf("nandsim %s", cmdopts->usagestring); 1163235537Sgber return (EX_USAGE); 1164235537Sgber } 1165235537Sgber retcode = cmdopts->commandfunc(argc, argv); 1166235537Sgber 1167235537Sgber if (retcode == EX_USAGE) { 1168235537Sgber /* Print command-specific usage */ 1169235537Sgber printf("nandsim %s", cmdopts->usagestring); 1170235537Sgber } else if (retcode == EX_OSFILE) { 1171235537Sgber error("Could not open device file"); 1172235537Sgber } 1173235537Sgber 1174235537Sgber } else { 1175235537Sgber error("Unknown command!"); 1176235537Sgber retcode = EX_USAGE; 1177235537Sgber } 1178235537Sgber } 1179235537Sgber return (retcode); 1180235537Sgber} 1181235537Sgber 1182235537Sgberstatic int 1183235537Sgbercmdhelp(int gargc __unused, char **gargv __unused) 1184235537Sgber{ 1185235537Sgber struct nandsim_command *opts; 1186235537Sgber 1187235537Sgber printf("usage: nandsim <command> [command params] [params]\n\n"); 1188235537Sgber 1189235537Sgber for (opts = commands; (opts != NULL) && 1190235537Sgber (opts->cmd_name != NULL); opts++) 1191235537Sgber printf("nandsim %s", opts->usagestring); 1192235537Sgber 1193235537Sgber printf("\n"); 1194235537Sgber return (EX_OK); 1195235537Sgber} 1196235537Sgber 1197235537Sgberstatic void 1198235537Sgberprintchip(struct sim_chip *chip, uint8_t verbose) 1199235537Sgber{ 1200235537Sgber 1201235537Sgber if (chip->created == 0) 1202235537Sgber return; 1203235537Sgber if (verbose > 0) { 1204235537Sgber printf("\n[Chip info]\n"); 1205235537Sgber printf("num= %d\nctrl_num=%d\ndevice_id=%02x" 1206235537Sgber "\tmanufacturer_id=%02x\ndevice_model=%s\nmanufacturer=" 1207235537Sgber "%s\ncol_addr_cycles=%d\nrow_addr_cycles=%d" 1208235537Sgber "\npage_size=%d\noob_size=%d\npages_per_block=%d\n" 1209235537Sgber "blocks_per_lun=%d\nluns=%d\n\nprog_time=%d\n" 1210235537Sgber "erase_time=%d\nread_time=%d\n" 1211235537Sgber "error_ratio=%d\nwear_level=%d\nwrite_protect=%c\n" 1212235537Sgber "chip_width=%db\n", chip->num, chip->ctrl_num, 1213235537Sgber chip->device_id, chip->manufact_id,chip->device_model, 1214235537Sgber chip->manufacturer, chip->col_addr_cycles, 1215235537Sgber chip->row_addr_cycles, chip->page_size, 1216235537Sgber chip->oob_size, chip->pgs_per_blk, chip->blks_per_lun, 1217235537Sgber chip->luns,chip->prog_time, chip->erase_time, 1218235537Sgber chip->read_time, chip->error_ratio, chip->wear_level, 1219235537Sgber (chip->is_wp == 0) ? 'N':'Y', chip->width); 1220235537Sgber } else { 1221235537Sgber printf("[Chip info]\n"); 1222235537Sgber printf("\tnum=%d\n\tdevice_model=%s\n\tmanufacturer=%s\n" 1223235537Sgber "\tpage_size=%d\n\twrite_protect=%s\n", 1224235537Sgber chip->num, chip->device_model, chip->manufacturer, 1225235537Sgber chip->page_size, (chip->is_wp == 0) ? "NO":"YES"); 1226235537Sgber } 1227235537Sgber} 1228235537Sgber 1229235537Sgberstatic void 1230235537Sgberprintctrl(struct sim_ctrl *ctrl) 1231235537Sgber{ 1232235537Sgber int i; 1233235537Sgber 1234235537Sgber if (ctrl->created == 0) { 1235235537Sgber printf(MSG_NOCTRL "\n", ctrl->num); 1236235537Sgber return; 1237235537Sgber } 1238235537Sgber printf("\n[Controller info]\n"); 1239235537Sgber printf("\trunning: %s\n", ctrl->running ? "yes" : "no"); 1240235537Sgber printf("\tnum cs: %d\n", ctrl->num_cs); 1241235537Sgber printf("\tecc: %d\n", ctrl->ecc); 1242235537Sgber printf("\tlog_filename: %s\n", ctrl->filename); 1243235537Sgber printf("\tecc_layout:"); 1244235537Sgber for (i = 0; i < MAX_ECC_BYTES; i++) { 1245235537Sgber if (ctrl->ecc_layout[i] == 0xffff) 1246235537Sgber break; 1247235537Sgber else 1248235537Sgber printf("%c%d", i%16 ? ' ' : '\n', 1249235537Sgber ctrl->ecc_layout[i]); 1250235537Sgber } 1251235537Sgber printf("\n"); 1252235537Sgber} 1253235537Sgber 1254235537Sgberstatic int 1255235537Sgberis_ctrl_running(int ctrl_no, int *running) 1256235537Sgber{ 1257235537Sgber struct sim_ctrl ctrl; 1258235537Sgber int err, fd; 1259235537Sgber 1260235537Sgber ctrl.num = ctrl_no; 1261235537Sgber if (opendev(&fd) != EX_OK) 1262235537Sgber return (EX_OSFILE); 1263235537Sgber 1264235537Sgber err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); 1265235537Sgber if (err) { 1266235537Sgber error(MSG_STATUSACQCTRL, ctrl_no); 1267235537Sgber close(fd); 1268235537Sgber return (err); 1269235537Sgber } 1270235537Sgber *running = ctrl.running; 1271235537Sgber close(fd); 1272235537Sgber return (0); 1273235537Sgber} 1274235537Sgber 1275235537Sgberstatic int 1276235537Sgberis_ctrl_created(int ctrl_no, int *created) 1277235537Sgber{ 1278235537Sgber struct sim_ctrl ctrl; 1279235537Sgber int err, fd; 1280235537Sgber 1281235537Sgber ctrl.num = ctrl_no; 1282235537Sgber 1283235537Sgber if (opendev(&fd) != EX_OK) 1284235537Sgber return (EX_OSFILE); 1285235537Sgber 1286235537Sgber err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); 1287235537Sgber if (err) { 1288235537Sgber error("Could not acquire conf for ctrl#%d", ctrl_no); 1289235537Sgber close(fd); 1290235537Sgber return (err); 1291235537Sgber } 1292235537Sgber *created = ctrl.created; 1293235537Sgber close(fd); 1294235537Sgber return (0); 1295235537Sgber} 1296235537Sgber 1297235537Sgberstatic int 1298235537Sgberis_chip_created(int ctrl_no, int chip_no, int *created) 1299235537Sgber{ 1300235537Sgber struct sim_chip chip; 1301235537Sgber int err, fd; 1302235537Sgber 1303235537Sgber chip.ctrl_num = ctrl_no; 1304235537Sgber chip.num = chip_no; 1305235537Sgber 1306235537Sgber if (opendev(&fd) != EX_OK) 1307235537Sgber return (EX_OSFILE); 1308235537Sgber 1309235537Sgber err = ioctl(fd, NANDSIM_STATUS_CHIP, &chip); 1310235537Sgber if (err) { 1311235537Sgber error("Could not acquire conf for chip#%d", chip_no); 1312235537Sgber close(fd); 1313235537Sgber return (err); 1314235537Sgber } 1315235537Sgber *created = chip.created; 1316235537Sgber close(fd); 1317235537Sgber return (0); 1318235537Sgber} 1319235537Sgber 1320235537Sgberstatic int 1321235537Sgberassert_chip_connected(int ctrl_no, int chip_no) 1322235537Sgber{ 1323235537Sgber int created, running; 1324235537Sgber 1325235537Sgber if (is_ctrl_created(ctrl_no, &created)) 1326235537Sgber return (0); 1327235537Sgber 1328235537Sgber if (!created) { 1329235537Sgber error(MSG_NOCTRL, ctrl_no); 1330235537Sgber return (0); 1331235537Sgber } 1332235537Sgber 1333235537Sgber if (is_chip_created(ctrl_no, chip_no, &created)) 1334235537Sgber return (0); 1335235537Sgber 1336235537Sgber if (!created) { 1337235537Sgber error(MSG_NOTCONFIGDCTRLCHIP, ctrl_no, chip_no); 1338235537Sgber return (0); 1339235537Sgber } 1340235537Sgber 1341235537Sgber if (is_ctrl_running(ctrl_no, &running)) 1342235537Sgber return (0); 1343235537Sgber 1344235537Sgber if (!running) { 1345235537Sgber error(MSG_NOTRUNNING, ctrl_no); 1346235537Sgber return (0); 1347235537Sgber } 1348235537Sgber 1349235537Sgber return (1); 1350235537Sgber} 1351235537Sgber 1352235537Sgberstatic int 1353235537Sgberprintstats(int ctrlno, int chipno, uint32_t pageno, int cdevd) 1354235537Sgber{ 1355235537Sgber struct page_stat_io pstats; 1356235537Sgber struct block_stat_io bstats; 1357235537Sgber struct chip_param_io cparams; 1358235537Sgber uint32_t blkidx; 1359235537Sgber int err; 1360235537Sgber 1361235537Sgber /* Gather information about chip */ 1362235537Sgber err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); 1363235537Sgber 1364235537Sgber if (err) { 1365235537Sgber error("Could not acquire chip info for chip attached to cs#" 1366235537Sgber "%d, ctrl#%d", chipno, ctrlno); 1367235537Sgber return (EX_SOFTWARE); 1368235537Sgber } 1369235537Sgber 1370235537Sgber blkidx = (pageno / cparams.pages_per_block); 1371235537Sgber bstats.block_num = blkidx; 1372235537Sgber 1373235537Sgber err = ioctl(cdevd, NAND_IO_BLOCK_STAT, &bstats); 1374235537Sgber if (err) { 1375235537Sgber error("Could not acquire block#%d statistics!", blkidx); 1376235537Sgber return (ENXIO); 1377235537Sgber } 1378235537Sgber 1379235537Sgber printf("Block #%d erased: %d\n", blkidx, bstats.block_erased); 1380235537Sgber pstats.page_num = pageno; 1381235537Sgber 1382235537Sgber err = ioctl(cdevd, NAND_IO_PAGE_STAT, &pstats); 1383235537Sgber if (err) { 1384235537Sgber error("Could not acquire page statistics!"); 1385235537Sgber return (ENXIO); 1386235537Sgber } 1387235537Sgber 1388235537Sgber debug("BLOCKIDX = %d PAGENO (REL. TO BLK) = %d\n", blkidx, 1389235537Sgber pstats.page_num); 1390235537Sgber 1391235537Sgber printf("Page#%d : reads:%d writes:%d \n\traw reads:%d raw writes:%d " 1392235537Sgber "\n\tecc_succeeded:%d ecc_corrected:%d ecc_failed:%d\n", 1393235537Sgber pstats.page_num, pstats.page_read, pstats.page_written, 1394235537Sgber pstats.page_raw_read, pstats.page_raw_written, 1395235537Sgber pstats.ecc_succeded, pstats.ecc_corrected, pstats.ecc_failed); 1396235537Sgber return (0); 1397235537Sgber} 1398