1249423Sdim/*- 2193323Sed * Copyright (C) 2009-2012 Semihalf 3353358Sdim * All rights reserved. 4353358Sdim * 5353358Sdim * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8327952Sdim * 1. Redistributions of source code must retain the above copyright 9296417Sdim * notice, this list of conditions and the following disclaimer. 10296417Sdim * 2. Redistributions in binary form must reproduce the above copyright 11296417Sdim * notice, this list of conditions and the following disclaimer in the 12327952Sdim * documentation and/or other materials provided with the distribution. 13193323Sed * 14193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15309124Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16234353Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17327952Sdim * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18243830Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19327952Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20327952Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23296417Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24296417Sdim * SUCH DAMAGE. 25327952Sdim */ 26249423Sdim 27249423Sdim/* 28249423Sdim * Control application for the NAND simulator. 29327952Sdim */ 30353358Sdim 31327952Sdim#include <sys/cdefs.h> 32296417Sdim__FBSDID("$FreeBSD$"); 33327952Sdim 34327952Sdim#include <sys/errno.h> 35327952Sdim#include <sys/ioctl.h> 36327952Sdim#include <sys/mman.h> 37327952Sdim#include <sys/stat.h> 38327952Sdim#include <sys/types.h> 39327952Sdim 40276479Sdim#include <dev/nand/nandsim.h> 41327952Sdim#include <dev/nand/nand_dev.h> 42327952Sdim 43327952Sdim#include <ctype.h> 44344779Sdim#include <fcntl.h> 45327952Sdim#include <getopt.h> 46327952Sdim#include <stdio.h> 47327952Sdim#include <stdlib.h> 48327952Sdim#include <string.h> 49327952Sdim#include <stdarg.h> 50327952Sdim#include <unistd.h> 51360784Sdim#include <stdlib.h> 52327952Sdim#include <limits.h> 53327952Sdim#include <sysexits.h> 54327952Sdim 55327952Sdim#include "nandsim_cfgparse.h" 56296417Sdim 57327952Sdim#define SIMDEVICE "/dev/nandsim.ioctl" 58296417Sdim 59321369Sdim#define error(fmt, args...) do { \ 60327952Sdim printf("ERROR: " fmt "\n", ##args); } while (0) 61327952Sdim 62327952Sdim#define warn(fmt, args...) do { \ 63327952Sdim printf("WARNING: " fmt "\n", ##args); } while (0) 64327952Sdim 65193323Sed#define DEBUG 66193323Sed#undef DEBUG 67276479Sdim 68276479Sdim#ifdef DEBUG 69193323Sed#define debug(fmt, args...) do { \ 70193323Sed printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0) 71344779Sdim#else 72193323Sed#define debug(fmt, args...) do {} while(0) 73314564Sdim#endif 74261991Sdim 75261991Sdim#define NANDSIM_RAM_LOG_SIZE 16384 76193323Sed 77296417Sdim#define MSG_NOTRUNNING "Controller#%d is not running.Please start" \ 78296417Sdim " it first." 79341825Sdim#define MSG_RUNNING "Controller#%d is already running!" 80353358Sdim#define MSG_CTRLCHIPNEEDED "You have to specify ctrl_no:cs_no pair!" 81193323Sed#define MSG_STATUSACQCTRLCHIP "Could not acquire status for ctrl#%d chip#%d" 82321369Sdim#define MSG_STATUSACQCTRL "Could not acquire status for ctrl#%d" 83360784Sdim#define MSG_NOCHIP "There is no such chip configured (chip#%d "\ 84321369Sdim "at ctrl#%d)!" 85321369Sdim 86321369Sdim#define MSG_NOCTRL "Controller#%d is not configured!" 87341825Sdim#define MSG_NOTCONFIGDCTRLCHIP "Chip connected to ctrl#%d at cs#%d " \ 88341825Sdim "is not configured." 89341825Sdim 90341825Sdimtypedef int (commandfunc_t)(int , char **); 91353358Sdim 92353358Sdimstatic struct nandsim_command *getcommand(char *); 93353358Sdimstatic int parse_devstring(char *, int *, int *); 94353358Sdimstatic void printchip(struct sim_chip *, uint8_t); 95193323Sedstatic void printctrl(struct sim_ctrl *); 96193323Sedstatic int opendev(int *); 97327952Sdimstatic commandfunc_t cmdstatus; 98327952Sdimstatic commandfunc_t cmdconf; 99327952Sdimstatic commandfunc_t cmdstart; 100327952Sdimstatic commandfunc_t cmdstop; 101321369Sdimstatic commandfunc_t cmdmod; 102321369Sdimstatic commandfunc_t cmderror; 103321369Sdimstatic commandfunc_t cmdbb; 104321369Sdimstatic commandfunc_t cmdfreeze; 105321369Sdimstatic commandfunc_t cmdlog; 106321369Sdimstatic commandfunc_t cmdstats; 107321369Sdimstatic commandfunc_t cmddump; 108321369Sdimstatic commandfunc_t cmdrestore; 109321369Sdimstatic commandfunc_t cmddestroy; 110321369Sdimstatic commandfunc_t cmdhelp; 111296417Sdimstatic int checkusage(int, int, char **); 112296417Sdimstatic int is_chip_created(int, int, int *); 113296417Sdimstatic int is_ctrl_created(int, int *); 114296417Sdimstatic int is_ctrl_running(int, int *); 115296417Sdimstatic int assert_chip_connected(int , int); 116249423Sdimstatic int printstats(int, int, uint32_t, int); 117321369Sdim 118296417Sdimstruct nandsim_command { 119296417Sdim const char *cmd_name; /* Command name */ 120249423Sdim commandfunc_t *commandfunc; /* Ptr to command function */ 121344779Sdim uint8_t req_argc; /* Mandatory arguments count */ 122344779Sdim const char *usagestring; /* Usage string */ 123344779Sdim}; 124344779Sdim 125296417Sdimstatic struct nandsim_command commands[] = { 126296417Sdim {"status", cmdstatus, 1, 127249423Sdim "status <ctl_no|--all|-a> [-v]\n" }, 128296417Sdim {"conf", cmdconf, 1, 129296417Sdim "conf <filename>\n" }, 130344779Sdim {"start", cmdstart, 1, 131296417Sdim "start <ctrl_no>\n" }, 132296417Sdim {"mod", cmdmod, 2, 133261991Sdim "mod [-l <loglevel>] | <ctl_no:cs_no> [-p <prog_time>]\n" 134296417Sdim "\t[-e <erase_time>] [-r <read_time>]\n" 135296417Sdim "\t[-E <error_ratio>] | [-h]\n" }, 136344779Sdim {"stop", cmdstop, 1, 137309124Sdim "stop <ctrl_no>\n" }, 138309124Sdim {"error", cmderror, 5, 139309124Sdim "error <ctrl_no:cs_no> <page_num> <column> <length> <pattern>\n" }, 140309124Sdim {"bb", cmdbb, 2, 141344779Sdim "bb <ctl_no:cs_no> [blk_num1,blk_num2,..] [-U] [-L]\n" }, 142344779Sdim {"freeze", cmdfreeze, 1, 143296417Sdim "freeze [ctrl_no]\n" }, 144344779Sdim {"log", cmdlog, 1, 145327952Sdim "log <ctrl_no|--all|-a>\n" }, 146249423Sdim {"stats", cmdstats, 2, 147296417Sdim "stats <ctrl_no:cs_no> <pagenumber>\n" }, 148327952Sdim {"dump", cmddump, 2, 149296417Sdim "dump <ctrl_no:cs_no> <filename>\n" }, 150249423Sdim {"restore", cmdrestore, 2, 151296417Sdim "restore <ctrl_no:chip_no> <filename>\n" }, 152344779Sdim {"destroy", cmddestroy, 1, 153327952Sdim "destroy <ctrl_no[:cs_no]|--all|-a>\n" }, 154344779Sdim {"help", cmdhelp, 0, 155296417Sdim "help [-v]" }, 156327952Sdim {NULL, NULL, 0, NULL}, 157296417Sdim}; 158296417Sdim 159296417Sdim 160249423Sdim/* Parse command name, and start appropriate function */ 161296417Sdimstatic struct nandsim_command* 162296417Sdimgetcommand(char *arg) 163344779Sdim{ 164296417Sdim struct nandsim_command *opts; 165296417Sdim 166296417Sdim for (opts = commands; (opts != NULL) && 167296417Sdim (opts->cmd_name != NULL); opts++) { 168193323Sed if (strcmp(opts->cmd_name, arg) == 0) 169296417Sdim return (opts); 170296417Sdim } 171344779Sdim return (NULL); 172193323Sed} 173296417Sdim 174296417Sdim/* 175296417Sdim * Parse given string in format <ctrl_no>:<cs_no>, if possible -- set 176296417Sdim * ctrl and/or cs, and return 0 (success) or 1 (in case of error). 177193323Sed * 178327952Sdim * ctrl == 0xff && chip == 0xff : '--all' flag specified 179344779Sdim * ctrl != 0xff && chip != 0xff : both ctrl & chip were specified 180344779Sdim * ctrl != 0xff && chip == 0xff : only ctrl was specified 181327952Sdim */ 182296417Sdimstatic int 183296417Sdimparse_devstring(char *str, int *ctrl, int *cs) 184296417Sdim{ 185296417Sdim char *tmpstr; 186296417Sdim unsigned int num = 0; 187296417Sdim 188296417Sdim /* Ignore white spaces at the beginning */ 189296417Sdim while (isspace(*str) && (*str != '\0')) 190296417Sdim str++; 191296417Sdim 192296417Sdim *ctrl = 0xff; 193296417Sdim *cs = 0xff; 194296417Sdim if (strcmp(str, "--all") == 0 || 195296417Sdim strcmp(str, "-a") == 0) { 196296417Sdim /* If --all or -a is specified, ctl==chip==0xff */ 197296417Sdim debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); 198296417Sdim return (0); 199296417Sdim } 200296417Sdim /* Separate token and try to convert it to int */ 201296417Sdim tmpstr = (char *)strtok(str, ":"); 202296417Sdim if ((tmpstr != NULL) && (*tmpstr != '\0')) { 203296417Sdim if (convert_arguint(tmpstr, &num) != 0) 204296417Sdim return (1); 205296417Sdim 206193323Sed if (num > MAX_SIM_DEV - 1) { 207296417Sdim error("Invalid ctrl_no supplied: %s. Valid ctrl_no " 208296417Sdim "value must lie between 0 and 3!", tmpstr); 209344779Sdim return (1); 210344779Sdim } 211344779Sdim 212193323Sed *ctrl = num; 213296417Sdim tmpstr = (char *)strtok(NULL, ":"); 214296417Sdim 215296417Sdim if ((tmpstr != NULL) && (*tmpstr != '\0')) { 216193323Sed if (convert_arguint(tmpstr, &num) != 0) 217344779Sdim return (1); 218344779Sdim 219344779Sdim /* Check if chip_no is valid */ 220344779Sdim if (num > MAX_CTRL_CS - 1) { 221344779Sdim error("Invalid chip_no supplied: %s. Valid " 222344779Sdim "chip_no value must lie between 0 and 3!", 223344779Sdim tmpstr); 224296417Sdim return (1); 225296417Sdim } 226193323Sed *cs = num; 227321369Sdim } 228321369Sdim } else 229321369Sdim /* Empty devstring supplied */ 230321369Sdim return (1); 231321369Sdim 232296417Sdim debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); 233296417Sdim return (0); 234321369Sdim} 235193323Sed 236193323Sedstatic int 237193323Sedopendev(int *fd) 238344779Sdim{ 239296417Sdim 240296417Sdim *fd = open(SIMDEVICE, O_RDWR); 241296417Sdim if (*fd == -1) { 242193323Sed error("Could not open simulator device file (%s)!", 243321369Sdim SIMDEVICE); 244321369Sdim return (EX_OSFILE); 245321369Sdim } 246321369Sdim return (EX_OK); 247321369Sdim} 248296417Sdim 249193323Sedstatic int 250296417Sdimopencdev(int *cdevd, int ctrl, int chip) 251193323Sed{ 252296417Sdim char fname[255]; 253344779Sdim 254344779Sdim sprintf(fname, "/dev/nandsim%d.%d", ctrl, chip); 255344779Sdim *cdevd = open(fname, O_RDWR); 256296417Sdim if (*cdevd == -1) 257296417Sdim return (EX_NOINPUT); 258296417Sdim 259193323Sed return (EX_OK); 260193323Sed} 261193323Sed 262353358Sdim/* 263353358Sdim * Check if given arguments count match requirements. If no, or 264353358Sdim * --help (-h) flag is specified -- return 1 (print usage) 265353358Sdim */ 266353358Sdimstatic int 267193323Sedcheckusage(int gargc, int argsreqd, char **gargv) 268193323Sed{ 269193323Sed 270344779Sdim if (gargc < argsreqd + 2 || (gargc >= (argsreqd + 2) && 271296417Sdim (strcmp(gargv[1], "--help") == 0 || 272193323Sed strcmp(gargv[1], "-h") == 0))) 273193323Sed return (1); 274193323Sed 275193323Sed return (0); 276193323Sed} 277193323Sed 278193323Sedstatic int 279193323Sedcmdstatus(int gargc, char **gargv) 280344779Sdim{ 281344779Sdim int chip = 0, ctl = 0, err = 0, fd, idx, idx2, start, stop; 282344779Sdim uint8_t verbose = 0; 283193323Sed struct sim_ctrl ctrlconf; 284193323Sed struct sim_chip chipconf; 285193323Sed 286321369Sdim err = parse_devstring(gargv[2], &ctl, &chip); 287321369Sdim if (err) { 288344779Sdim return (EX_USAGE); 289193323Sed } else if (ctl == 0xff) { 290344779Sdim /* Every controller */ 291344779Sdim start = 0; 292344779Sdim stop = MAX_SIM_DEV-1; 293344779Sdim } else { 294344779Sdim /* Specified controller only */ 295344779Sdim start = ctl; 296344779Sdim stop = ctl; 297193323Sed } 298344779Sdim 299344779Sdim if (opendev(&fd) != EX_OK) 300344779Sdim return (EX_OSFILE); 301344779Sdim 302193323Sed for (idx = 0; idx < gargc; idx ++) 303344779Sdim if (strcmp(gargv[idx], "-v") == 0 || 304344779Sdim strcmp(gargv[idx], "--verbose") == 0) 305344779Sdim verbose = 1; 306193323Sed 307193323Sed for (idx = start; idx <= stop; idx++) { 308193323Sed ctrlconf.num = idx; 309193323Sed err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrlconf); 310193323Sed if (err) { 311193323Sed err = EX_SOFTWARE; 312193323Sed error(MSG_STATUSACQCTRL, idx); 313193323Sed continue; 314234353Sdim } 315327952Sdim 316296417Sdim printctrl(&ctrlconf); 317296417Sdim 318296417Sdim for (idx2 = 0; idx2 < MAX_CTRL_CS; idx2++) { 319296417Sdim chipconf.num = idx2; 320296417Sdim chipconf.ctrl_num = idx; 321296417Sdim 322296417Sdim err = ioctl(fd, NANDSIM_STATUS_CHIP, &chipconf); 323234353Sdim if (err) { 324296417Sdim err = EX_SOFTWARE; 325296417Sdim error(MSG_STATUSACQCTRL, idx); 326296417Sdim continue; 327327952Sdim } 328234353Sdim 329296417Sdim printchip(&chipconf, verbose); 330234353Sdim } 331296417Sdim } 332296417Sdim close(fd); 333296417Sdim return (err); 334296417Sdim} 335296417Sdim 336296417Sdimstatic int 337296417Sdimcmdconf(int gargc __unused, char **gargv) 338234353Sdim{ 339296417Sdim int err; 340296417Sdim 341234353Sdim err = parse_config(gargv[2], SIMDEVICE); 342327952Sdim if (err) 343234353Sdim return (EX_DATAERR); 344296417Sdim 345296417Sdim return (EX_OK); 346296417Sdim} 347234353Sdim 348296417Sdimstatic int 349296417Sdimcmdstart(int gargc __unused, char **gargv) 350296417Sdim{ 351296417Sdim int chip = 0, ctl = 0, err = 0, fd, running, state; 352296417Sdim 353296417Sdim err = parse_devstring(gargv[2], &ctl, &chip); 354296417Sdim if (err) 355234353Sdim return (EX_USAGE); 356296417Sdim 357296417Sdim err = is_ctrl_created(ctl, &state); 358296417Sdim if (err) { 359296417Sdim return (EX_SOFTWARE); 360327952Sdim } else if (state == 0) { 361234353Sdim error(MSG_NOCTRL, ctl); 362296417Sdim return (EX_SOFTWARE); 363234353Sdim } 364296417Sdim 365296417Sdim err = is_ctrl_running(ctl, &running); 366296417Sdim if (err) 367296417Sdim return (EX_SOFTWARE); 368296417Sdim 369296417Sdim if (running) { 370234353Sdim warn(MSG_RUNNING, ctl); 371296417Sdim } else { 372309124Sdim if (opendev(&fd) != EX_OK) 373296417Sdim return (EX_OSFILE); 374296417Sdim 375296417Sdim err = ioctl(fd, NANDSIM_START_CTRL, &ctl); 376234353Sdim close(fd); 377296417Sdim if (err) { 378296417Sdim error("Cannot start controller#%d", ctl); 379296417Sdim err = EX_SOFTWARE; 380296417Sdim } 381296417Sdim } 382296417Sdim return (err); 383296417Sdim} 384296417Sdim 385296417Sdimstatic int 386296417Sdimcmdstop(int gargc __unused, char **gargv) 387296417Sdim{ 388296417Sdim int chip = 0, ctl = 0, err = 0, fd, running; 389296417Sdim 390296417Sdim err = parse_devstring(gargv[2], &ctl, &chip); 391296417Sdim if (err) 392296417Sdim return (EX_USAGE); 393296417Sdim 394296417Sdim err = is_ctrl_running(ctl, &running); 395296417Sdim if (err) 396296417Sdim return (EX_SOFTWARE); 397234353Sdim 398234353Sdim if (!running) { 399296417Sdim error(MSG_NOTRUNNING, ctl); 400296417Sdim } else { 401296417Sdim if (opendev(&fd) != EX_OK) 402296417Sdim return (EX_OSFILE); 403296417Sdim 404234353Sdim err = ioctl(fd, NANDSIM_STOP_CTRL, &ctl); 405296417Sdim close(fd); 406296417Sdim if (err) { 407296417Sdim error("Cannot stop controller#%d", ctl); 408296417Sdim err = EX_SOFTWARE; 409327952Sdim } 410327952Sdim } 411296417Sdim 412327952Sdim return (err); 413327952Sdim} 414327952Sdim 415296417Sdimstatic int 416296417Sdimcmdmod(int gargc __unused, char **gargv) 417234353Sdim{ 418327952Sdim int chip, ctl, err = 0, fd = -1, i; 419327952Sdim struct sim_mod mods; 420234353Sdim 421327952Sdim if (gargc >= 4) { 422296417Sdim if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2], 423327952Sdim "-l") == 0) { 424327952Sdim /* Set loglevel (ctrl:chip pair independent) */ 425234353Sdim mods.field = SIM_MOD_LOG_LEVEL; 426314564Sdim 427314564Sdim if (convert_arguint(gargv[3], &mods.new_value) != 0) 428314564Sdim return (EX_SOFTWARE); 429296417Sdim 430327952Sdim if (opendev(&fd) != EX_OK) 431296417Sdim return (EX_OSFILE); 432296417Sdim 433314564Sdim err = ioctl(fd, NANDSIM_MODIFY, &mods); 434327952Sdim if (err) { 435296417Sdim error("simulator parameter %s could not be " 436296417Sdim "modified !", gargv[3]); 437296417Sdim close(fd); 438327952Sdim return (EX_SOFTWARE); 439296417Sdim } 440296417Sdim 441234353Sdim debug("request : loglevel = %d\n", mods.new_value); 442327952Sdim close(fd); 443327952Sdim return (EX_OK); 444296417Sdim } 445261991Sdim } 446261991Sdim 447296417Sdim err = parse_devstring(gargv[2], &ctl, &chip); 448296417Sdim if (err) 449341825Sdim return (EX_USAGE); 450296417Sdim 451276479Sdim else if (chip == 0xff) { 452276479Sdim error(MSG_CTRLCHIPNEEDED); 453276479Sdim return (EX_USAGE); 454276479Sdim } 455261991Sdim 456261991Sdim if (!assert_chip_connected(ctl, chip)) 457261991Sdim return (EX_SOFTWARE); 458276479Sdim 459276479Sdim if (opendev(&fd) != EX_OK) 460276479Sdim return (EX_OSFILE); 461261991Sdim 462261991Sdim /* Find out which flags were passed */ 463261991Sdim for (i = 3; i < gargc; i++) { 464261991Sdim 465261991Sdim if (convert_arguint(gargv[i + 1], &mods.new_value) != 0) 466261991Sdim continue; 467261991Sdim 468261991Sdim if (strcmp(gargv[i], "--prog-time") == 0 || 469261991Sdim strcmp(gargv[i], "-p") == 0) { 470261991Sdim 471261991Sdim mods.field = SIM_MOD_PROG_TIME; 472276479Sdim debug("request : progtime = %d\n", mods.new_value); 473261991Sdim 474276479Sdim } else if (strcmp(gargv[i], "--erase-time") == 0 || 475280031Sdim strcmp(gargv[i], "-e") == 0) { 476276479Sdim 477261991Sdim mods.field = SIM_MOD_ERASE_TIME; 478261991Sdim debug("request : eraseime = %d\n", mods.new_value); 479261991Sdim 480261991Sdim } else if (strcmp(gargv[i], "--read-time") == 0 || 481276479Sdim strcmp(gargv[i], "-r") == 0) { 482276479Sdim 483276479Sdim mods.field = SIM_MOD_READ_TIME; 484276479Sdim debug("request : read_time = %d\n", mods.new_value); 485276479Sdim 486276479Sdim } else if (strcmp(gargv[i], "--error-ratio") == 0 || 487276479Sdim strcmp(gargv[i], "-E") == 0) { 488276479Sdim 489280031Sdim mods.field = SIM_MOD_ERROR_RATIO; 490276479Sdim debug("request : error_ratio = %d\n", mods.new_value); 491276479Sdim 492276479Sdim } else { 493261991Sdim /* Flag not recognized, or nothing specified. */ 494276479Sdim error("Unrecognized flag:%s\n", gargv[i]); 495276479Sdim if (fd >= 0) 496261991Sdim close(fd); 497276479Sdim return (EX_USAGE); 498261991Sdim } 499261991Sdim 500261991Sdim mods.chip_num = chip; 501261991Sdim mods.ctrl_num = ctl; 502261991Sdim 503276479Sdim /* Call appropriate ioctl */ 504261991Sdim err = ioctl(fd, NANDSIM_MODIFY, &mods); 505261991Sdim if (err) { 506261991Sdim error("simulator parameter %s could not be modified! ", 507261991Sdim gargv[i]); 508261991Sdim continue; 509296417Sdim } 510296417Sdim i++; 511296417Sdim } 512296417Sdim close(fd); 513296417Sdim return (EX_OK); 514296417Sdim} 515296417Sdim 516296417Sdimstatic int 517296417Sdimcmderror(int gargc __unused, char **gargv) 518296417Sdim{ 519296417Sdim uint32_t page, column, len, pattern; 520296417Sdim int chip = 0, ctl = 0, err = 0, fd; 521296417Sdim struct sim_error sim_err; 522296417Sdim 523296417Sdim err = parse_devstring(gargv[2], &ctl, &chip); 524296417Sdim if (err) 525296417Sdim return (EX_USAGE); 526296417Sdim 527261991Sdim if (chip == 0xff) { 528296417Sdim error(MSG_CTRLCHIPNEEDED); 529296417Sdim return (EX_USAGE); 530296417Sdim } 531296417Sdim 532296417Sdim if (convert_arguint(gargv[3], &page) || 533296417Sdim convert_arguint(gargv[4], &column) || 534296417Sdim convert_arguint(gargv[5], &len) || 535314564Sdim convert_arguint(gargv[6], &pattern)) 536314564Sdim return (EX_SOFTWARE); 537296417Sdim 538296417Sdim if (!assert_chip_connected(ctl, chip)) 539296417Sdim return (EX_SOFTWARE); 540296417Sdim 541296417Sdim sim_err.page_num = page; 542296417Sdim sim_err.column = column; 543296417Sdim sim_err.len = len; 544296417Sdim sim_err.pattern = pattern; 545296417Sdim sim_err.ctrl_num = ctl; 546296417Sdim sim_err.chip_num = chip; 547276479Sdim 548261991Sdim if (opendev(&fd) != EX_OK) 549261991Sdim return (EX_OSFILE); 550261991Sdim 551261991Sdim err = ioctl(fd, NANDSIM_INJECT_ERROR, &sim_err); 552309124Sdim 553309124Sdim close(fd); 554309124Sdim if (err) { 555309124Sdim error("Could not inject error !"); 556309124Sdim return (EX_SOFTWARE); 557261991Sdim } 558261991Sdim return (EX_OK); 559261991Sdim} 560261991Sdim 561261991Sdimstatic int 562261991Sdimcmdbb(int gargc, char **gargv) 563261991Sdim{ 564261991Sdim struct sim_block_state bs; 565261991Sdim struct chip_param_io cparams; 566261991Sdim uint32_t blkidx; 567261991Sdim int c, cdevd, chip = 0, ctl = 0, err = 0, fd, idx; 568261991Sdim uint8_t flagL = 0, flagU = 0; 569261991Sdim int *badblocks = NULL; 570261991Sdim 571261991Sdim /* Check for --list/-L or --unmark/-U flags */ 572314564Sdim for (idx = 3; idx < gargc; idx++) { 573314564Sdim if (strcmp(gargv[idx], "--list") == 0 || 574314564Sdim strcmp(gargv[idx], "-L") == 0) 575314564Sdim flagL = idx; 576314564Sdim if (strcmp(gargv[idx], "--unmark") == 0 || 577314564Sdim strcmp(gargv[idx], "-U") == 0) 578314564Sdim flagU = idx; 579314564Sdim } 580314564Sdim 581314564Sdim if (flagL == 2 || flagU == 2 || flagU == 3) 582314564Sdim return (EX_USAGE); 583314564Sdim 584314564Sdim err = parse_devstring(gargv[2], &ctl, &chip); 585314564Sdim if (err) { 586314564Sdim return (EX_USAGE); 587314564Sdim } 588327952Sdim if (chip == 0xff || ctl == 0xff) { 589327952Sdim error(MSG_CTRLCHIPNEEDED); 590314564Sdim return (EX_USAGE); 591314564Sdim } 592314564Sdim 593314564Sdim bs.ctrl_num = ctl; 594314564Sdim bs.chip_num = chip; 595314564Sdim 596314564Sdim if (!assert_chip_connected(ctl, chip)) 597314564Sdim return (EX_SOFTWARE); 598314564Sdim 599314564Sdim if (opencdev(&cdevd, ctl, chip) != EX_OK) 600314564Sdim return (EX_OSFILE); 601314564Sdim 602314564Sdim err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); 603314564Sdim if (err) 604314564Sdim return (EX_SOFTWARE); 605314564Sdim 606314564Sdim close(cdevd); 607314564Sdim 608314564Sdim bs.ctrl_num = ctl; 609314564Sdim bs.chip_num = chip; 610314564Sdim 611314564Sdim if (opendev(&fd) != EX_OK) 612314564Sdim return (EX_OSFILE); 613321369Sdim 614314564Sdim if (flagL != 3) { 615314564Sdim /* 616314564Sdim * Flag -L was specified either after blocklist or was not 617314564Sdim * specified at all. 618314564Sdim */ 619314564Sdim c = parse_intarray(gargv[3], &badblocks); 620314564Sdim 621314564Sdim for (idx = 0; idx < c; idx++) { 622321369Sdim bs.block_num = badblocks[idx]; 623321369Sdim /* Do not change wearout */ 624321369Sdim bs.wearout = -1; 625321369Sdim bs.state = (flagU == 0) ? NANDSIM_BAD_BLOCK : 626321369Sdim NANDSIM_GOOD_BLOCK; 627321369Sdim 628321369Sdim err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); 629321369Sdim if (err) { 630321369Sdim error("Could not set bad block(%d) for " 631321369Sdim "controller (%d)!", 632321369Sdim badblocks[idx], ctl); 633321369Sdim err = EX_SOFTWARE; 634321369Sdim break; 635321369Sdim } 636321369Sdim } 637321369Sdim } 638321369Sdim if (flagL != 0) { 639321369Sdim /* If flag -L was specified (anywhere) */ 640321369Sdim for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 641321369Sdim bs.block_num = blkidx; 642321369Sdim /* Do not change the wearout */ 643321369Sdim bs.wearout = -1; 644321369Sdim err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); 645321369Sdim if (err) { 646321369Sdim error("Could not acquire block state"); 647321369Sdim err = EX_SOFTWARE; 648321369Sdim continue; 649321369Sdim } 650321369Sdim printf("Block#%d: wear count: %d %s\n", blkidx, 651321369Sdim bs.wearout, 652321369Sdim (bs.state == NANDSIM_BAD_BLOCK) ? "BAD":"GOOD"); 653321369Sdim } 654321369Sdim } 655321369Sdim close(fd); 656321369Sdim return (err); 657321369Sdim} 658321369Sdim 659321369Sdimstatic int 660321369Sdimcmdfreeze(int gargc __unused, char **gargv) 661341825Sdim{ 662321369Sdim int chip = 0, ctl = 0, err = 0, fd, i, start = 0, state, stop = 0; 663321369Sdim struct sim_ctrl_chip ctrlchip; 664321369Sdim 665360784Sdim err = parse_devstring(gargv[2], &ctl, &chip); 666360784Sdim if (err) 667360784Sdim return (EX_USAGE); 668360784Sdim 669360784Sdim if (ctl == 0xff) { 670360784Sdim error("You have to specify at least controller number"); 671360784Sdim return (EX_USAGE); 672360784Sdim } 673360784Sdim 674360784Sdim if (ctl != 0xff && chip == 0xff) { 675360784Sdim start = 0; 676360784Sdim stop = MAX_CTRL_CS - 1; 677360784Sdim } else { 678360784Sdim start = chip; 679360784Sdim stop = chip; 680360784Sdim } 681360784Sdim 682360784Sdim ctrlchip.ctrl_num = ctl; 683360784Sdim 684296417Sdim err = is_ctrl_running(ctl, &state); 685296417Sdim if (err) 686193323Sed return (EX_SOFTWARE); 687193323Sed if (state == 0) { 688234353Sdim error(MSG_NOTRUNNING, ctl); 689234353Sdim return (EX_SOFTWARE); 690193323Sed } 691193323Sed 692296417Sdim if (opendev(&fd) != EX_OK) 693309124Sdim return (EX_OSFILE); 694309124Sdim 695309124Sdim for (i = start; i <= stop; i++) { 696309124Sdim err = is_chip_created(ctl, i, &state); 697193323Sed if (err) 698193323Sed return (EX_SOFTWARE); 699321369Sdim else if (state == 0) { 700321369Sdim continue; 701234353Sdim } 702234353Sdim 703234353Sdim ctrlchip.chip_num = i; 704234353Sdim err = ioctl(fd, NANDSIM_FREEZE, &ctrlchip); 705296417Sdim if (err) { 706296417Sdim error("Could not freeze ctrl#%d chip#%d", ctl, i); 707234353Sdim close(fd); 708321369Sdim return (EX_SOFTWARE); 709234353Sdim } 710234353Sdim } 711234353Sdim close(fd); 712234353Sdim return (EX_OK); 713234353Sdim} 714234353Sdim 715234353Sdimstatic int 716296417Sdimcmdlog(int gargc __unused, char **gargv) 717296417Sdim{ 718296417Sdim struct sim_log log; 719296417Sdim int chip = 0, ctl = 0, err = 0, fd, idx, start = 0, stop = 0; 720261991Sdim char *logbuf; 721261991Sdim 722234353Sdim err = parse_devstring(gargv[2], &ctl, &chip); 723296417Sdim if (err) 724234353Sdim return (EX_USAGE); 725234353Sdim 726234353Sdim logbuf = (char *)malloc(sizeof(char) * NANDSIM_RAM_LOG_SIZE); 727321369Sdim if (logbuf == NULL) { 728234353Sdim error("Not enough memory to create log buffer"); 729234353Sdim return (EX_SOFTWARE); 730234353Sdim } 731234353Sdim 732234353Sdim memset(logbuf, 0, NANDSIM_RAM_LOG_SIZE); 733234353Sdim log.log = logbuf; 734296417Sdim log.len = NANDSIM_RAM_LOG_SIZE; 735309124Sdim 736309124Sdim if (ctl == 0xff) { 737309124Sdim start = 0; 738261991Sdim stop = MAX_SIM_DEV-1; 739261991Sdim } else { 740234353Sdim start = ctl; 741234353Sdim stop = ctl; 742234353Sdim } 743234353Sdim 744261991Sdim if (opendev(&fd) != EX_OK) { 745261991Sdim free(logbuf); 746261991Sdim return (EX_OSFILE); 747261991Sdim } 748261991Sdim 749296417Sdim /* Print logs for selected controller(s) */ 750296417Sdim for (idx = start; idx <= stop; idx++) { 751296417Sdim log.ctrl_num = idx; 752360784Sdim 753360784Sdim err = ioctl(fd, NANDSIM_PRINT_LOG, &log); 754261991Sdim if (err) { 755261991Sdim error("Could not get log for controller %d!", idx); 756234353Sdim continue; 757234353Sdim } 758234353Sdim 759234353Sdim printf("Logs for controller#%d:\n%s\n", idx, logbuf); 760234353Sdim } 761234353Sdim 762234353Sdim free(logbuf); 763234353Sdim close(fd); 764234353Sdim return (EX_OK); 765296417Sdim} 766276479Sdim 767234353Sdimstatic int 768296417Sdimcmdstats(int gargc __unused, char **gargv) 769296417Sdim{ 770234353Sdim int cdevd, chip = 0, ctl = 0, err = 0; 771234353Sdim uint32_t pageno = 0; 772234353Sdim 773234353Sdim err = parse_devstring(gargv[2], &ctl, &chip); 774261991Sdim 775321369Sdim if (err) 776193323Sed return (EX_USAGE); 777193323Sed 778193323Sed if (chip == 0xff) { 779234353Sdim error(MSG_CTRLCHIPNEEDED); 780234353Sdim return (EX_USAGE); 781234353Sdim } 782234353Sdim 783276479Sdim if (convert_arguint(gargv[3], &pageno) != 0) 784276479Sdim return (EX_USAGE); 785234353Sdim 786234353Sdim if (!assert_chip_connected(ctl, chip)) 787234353Sdim return (EX_SOFTWARE); 788234353Sdim 789234353Sdim if (opencdev(&cdevd, ctl, chip) != EX_OK) 790234353Sdim return (EX_OSFILE); 791296417Sdim 792296417Sdim err = printstats(ctl, chip, pageno, cdevd); 793234353Sdim if (err) { 794296417Sdim close(cdevd); 795234353Sdim return (EX_SOFTWARE); 796234353Sdim } 797309124Sdim close(cdevd); 798309124Sdim return (EX_OK); 799234353Sdim} 800234353Sdim 801276479Sdimstatic int 802276479Sdimcmddump(int gargc __unused, char **gargv) 803234353Sdim{ 804309124Sdim struct sim_dump dump; 805309124Sdim struct sim_block_state bs; 806234353Sdim struct chip_param_io cparams; 807234353Sdim int chip = 0, ctl = 0, err = EX_OK, fd, dumpfd; 808234353Sdim uint32_t blkidx, bwritten = 0, totalwritten = 0; 809234353Sdim void *buf; 810234353Sdim 811234353Sdim err = parse_devstring(gargv[2], &ctl, &chip); 812296417Sdim if (err) 813296417Sdim return (EX_USAGE); 814234353Sdim 815234353Sdim if (chip == 0xff || ctl == 0xff) { 816234353Sdim error(MSG_CTRLCHIPNEEDED); 817321369Sdim return (EX_USAGE); 818234353Sdim } 819234353Sdim 820234353Sdim if (!assert_chip_connected(ctl, chip)) 821261991Sdim return (EX_SOFTWARE); 822261991Sdim 823261991Sdim if (opencdev(&fd, ctl, chip) != EX_OK) 824261991Sdim return (EX_OSFILE); 825261991Sdim 826261991Sdim err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); 827261991Sdim if (err) { 828261991Sdim error("Cannot get parameters for chip %d:%d", ctl, chip); 829261991Sdim close(fd); 830261991Sdim return (EX_SOFTWARE); 831261991Sdim } 832261991Sdim close(fd); 833261991Sdim 834261991Sdim dump.ctrl_num = ctl; 835261991Sdim dump.chip_num = chip; 836261991Sdim 837261991Sdim dump.len = cparams.pages_per_block * (cparams.page_size + 838261991Sdim cparams.oob_size); 839261991Sdim 840261991Sdim buf = malloc(dump.len); 841261991Sdim if (buf == NULL) { 842261991Sdim error("Could not allocate memory!"); 843261991Sdim return (EX_SOFTWARE); 844261991Sdim } 845261991Sdim dump.data = buf; 846261991Sdim 847261991Sdim errno = 0; 848261991Sdim dumpfd = open(gargv[3], O_WRONLY | O_CREAT, 0666); 849261991Sdim if (dumpfd == -1) { 850360784Sdim error("Cannot create dump file."); 851261991Sdim free(buf); 852261991Sdim return (EX_SOFTWARE); 853193323Sed } 854193323Sed 855193323Sed if (opendev(&fd)) { 856193323Sed close(dumpfd); 857193323Sed free(buf); 858296417Sdim return (EX_SOFTWARE); 859296417Sdim } 860296417Sdim 861296417Sdim bs.ctrl_num = ctl; 862296417Sdim bs.chip_num = chip; 863243830Sdim 864309124Sdim /* First uint32_t in file shall contain block count */ 865309124Sdim if (write(dumpfd, &cparams, sizeof(cparams)) < (int)sizeof(cparams)) { 866193323Sed error("Error writing to dumpfile!"); 867193323Sed close(fd); 868193323Sed close(dumpfd); 869243830Sdim free(buf); 870193323Sed return (EX_SOFTWARE); 871193323Sed } 872193323Sed 873193323Sed /* 874193323Sed * First loop acquires blocks states and writes them to 875193323Sed * the dump file. 876193323Sed */ 877193323Sed for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 878193323Sed bs.block_num = blkidx; 879193323Sed err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); 880193323Sed if (err) { 881193323Sed error("Could not get bad block(%d) for " 882193323Sed "controller (%d)!", blkidx, ctl); 883296417Sdim close(fd); 884296417Sdim close(dumpfd); 885296417Sdim free(buf); 886296417Sdim return (EX_SOFTWARE); 887296417Sdim } 888296417Sdim 889296417Sdim bwritten = write(dumpfd, &bs, sizeof(bs)); 890296417Sdim if (bwritten != sizeof(bs)) { 891296417Sdim error("Error writing to dumpfile"); 892296417Sdim close(fd); 893296417Sdim close(dumpfd); 894296417Sdim free(buf); 895296417Sdim return (EX_SOFTWARE); 896296417Sdim } 897296417Sdim } 898296417Sdim 899296417Sdim /* Second loop dumps the data */ 900296417Sdim for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 901193323Sed debug("Block#%d...", blkidx); 902296417Sdim dump.block_num = blkidx; 903296417Sdim 904296417Sdim err = ioctl(fd, NANDSIM_DUMP, &dump); 905296417Sdim if (err) { 906296417Sdim error("Could not dump ctrl#%d chip#%d " 907296417Sdim "block#%d", ctl, chip, blkidx); 908321369Sdim err = EX_SOFTWARE; 909193323Sed break; 910296417Sdim } 911296417Sdim 912314564Sdim bwritten = write(dumpfd, dump.data, dump.len); 913314564Sdim if (bwritten != dump.len) { 914296417Sdim error("Error writing to dumpfile"); 915296417Sdim err = EX_SOFTWARE; 916193323Sed break; 917193323Sed } 918199989Srdivacky debug("OK!\n"); 919193323Sed totalwritten += bwritten; 920193323Sed } 921193323Sed printf("%d out of %d B written.\n", totalwritten, dump.len * blkidx); 922193323Sed 923193323Sed close(fd); 924193323Sed close(dumpfd); 925296417Sdim free(buf); 926296417Sdim return (err); 927193323Sed} 928193323Sed 929296417Sdimstatic int 930193323Sedcmdrestore(int gargc __unused, char **gargv) 931321369Sdim{ 932193323Sed struct sim_dump dump; 933193323Sed struct sim_block_state bs; 934309124Sdim struct stat filestat; 935309124Sdim int chip = 0, ctl = 0, err = 0, fd, dumpfd = -1; 936309124Sdim uint32_t blkidx, blksz, fsize = 0, expfilesz; 937309124Sdim void *buf; 938193323Sed struct chip_param_io cparams, dumpcparams; 939193323Sed 940296417Sdim err = parse_devstring(gargv[2], &ctl, &chip); 941193323Sed if (err) 942204642Srdivacky return (EX_USAGE); 943193323Sed else if (ctl == 0xff) { 944193323Sed error(MSG_CTRLCHIPNEEDED); 945296417Sdim return (EX_USAGE); 946193323Sed } 947193323Sed 948193323Sed if (!assert_chip_connected(ctl, chip)) 949193323Sed return (EX_SOFTWARE); 950296417Sdim 951321369Sdim /* Get chip geometry */ 952321369Sdim if (opencdev(&fd, ctl, chip) != EX_OK) 953193323Sed return (EX_OSFILE); 954193323Sed 955321369Sdim err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); 956193323Sed if (err) { 957193323Sed error("Cannot get parameters for chip %d:%d", ctl, chip); 958193323Sed close(fd); 959193323Sed return (err); 960193323Sed } 961193323Sed close(fd); 962193323Sed 963296417Sdim /* Obtain dump file size */ 964296417Sdim errno = 0; 965296417Sdim if (stat(gargv[3], &filestat) != 0) { 966296417Sdim error("Could not acquire file size! : %s", 967296417Sdim strerror(errno)); 968296417Sdim return (EX_IOERR); 969296417Sdim } 970296417Sdim 971309124Sdim fsize = filestat.st_size; 972296417Sdim blksz = cparams.pages_per_block * (cparams.page_size + 973296417Sdim cparams.oob_size); 974296417Sdim 975280031Sdim /* Expected dump file size for chip */ 976296417Sdim expfilesz = cparams.blocks * (blksz + sizeof(bs)) + sizeof(cparams); 977296417Sdim 978296417Sdim if (fsize != expfilesz) { 979296417Sdim error("File size does not match chip geometry (file size: %d" 980249423Sdim ", dump size: %d)", fsize, expfilesz); 981327952Sdim return (EX_SOFTWARE); 982327952Sdim } 983296417Sdim 984296417Sdim dumpfd = open(gargv[3], O_RDONLY); 985296417Sdim if (dumpfd == -1) { 986296417Sdim error("Could not open dump file!"); 987327952Sdim return (EX_IOERR); 988296417Sdim } 989296417Sdim 990296417Sdim /* Read chip params saved in dumpfile */ 991296417Sdim read(dumpfd, &dumpcparams, sizeof(dumpcparams)); 992296417Sdim 993296417Sdim /* XXX */ 994249423Sdim if (bcmp(&dumpcparams, &cparams, sizeof(cparams)) != 0) { 995296417Sdim error("Supplied dump is created for a chip with different " 996296417Sdim "chip configuration!"); 997296417Sdim close(dumpfd); 998296417Sdim return (EX_SOFTWARE); 999296417Sdim } 1000296417Sdim 1001296417Sdim if (opendev(&fd) != EX_OK) { 1002296417Sdim close(dumpfd); 1003296417Sdim return (EX_OSFILE); 1004296417Sdim } 1005296417Sdim 1006296417Sdim buf = malloc(blksz); 1007296417Sdim if (buf == NULL) { 1008296417Sdim error("Could not allocate memory for block buffer"); 1009296417Sdim close(dumpfd); 1010296417Sdim close(fd); 1011296417Sdim return (EX_SOFTWARE); 1012296417Sdim } 1013296417Sdim 1014296417Sdim dump.ctrl_num = ctl; 1015296417Sdim dump.chip_num = chip; 1016296417Sdim dump.data = buf; 1017296417Sdim /* Restore block states and wearouts */ 1018296417Sdim for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 1019296417Sdim dump.block_num = blkidx; 1020296417Sdim if (read(dumpfd, &bs, sizeof(bs)) != sizeof(bs)) { 1021296417Sdim error("Error reading dumpfile"); 1022296417Sdim close(dumpfd); 1023296417Sdim close(fd); 1024249423Sdim free(buf); 1025296417Sdim return (EX_SOFTWARE); 1026296417Sdim } 1027296417Sdim bs.ctrl_num = ctl; 1028296417Sdim bs.chip_num = chip; 1029296417Sdim debug("BLKIDX=%d BLOCKS=%d CTRL=%d CHIP=%d STATE=%d\n" 1030249423Sdim "WEAROUT=%d BS.CTRL_NUM=%d BS.CHIP_NUM=%d\n", 1031249423Sdim blkidx, cparams.blocks, dump.ctrl_num, dump.chip_num, 1032249423Sdim bs.state, bs.wearout, bs.ctrl_num, bs.chip_num); 1033249423Sdim 1034249423Sdim err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); 1035296417Sdim if (err) { 1036309124Sdim error("Could not set bad block(%d) for " 1037296417Sdim "controller: %d, chip: %d!", blkidx, ctl, chip); 1038296417Sdim close(dumpfd); 1039296417Sdim close(fd); 1040296417Sdim free(buf); 1041249423Sdim return (EX_SOFTWARE); 1042249423Sdim } 1043296417Sdim } 1044296417Sdim /* Restore data */ 1045296417Sdim for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 1046296417Sdim errno = 0; 1047321369Sdim dump.len = read(dumpfd, buf, blksz); 1048296417Sdim if (errno) { 1049296417Sdim error("Failed to read block#%d from dumpfile.", blkidx); 1050249423Sdim err = EX_SOFTWARE; 1051309124Sdim break; 1052309124Sdim } 1053309124Sdim dump.block_num = blkidx; 1054309124Sdim err = ioctl(fd, NANDSIM_RESTORE, &dump); 1055296417Sdim if (err) { 1056296417Sdim error("Could not restore block#%d of ctrl#%d chip#%d" 1057296417Sdim ": %s", blkidx, ctl, chip, strerror(errno)); 1058296417Sdim err = EX_SOFTWARE; 1059296417Sdim break; 1060296417Sdim } 1061296417Sdim } 1062296417Sdim 1063309124Sdim free(buf); 1064296417Sdim close(dumpfd); 1065296417Sdim close(fd); 1066296417Sdim return (err); 1067341825Sdim 1068341825Sdim} 1069321369Sdim 1070296417Sdimstatic int 1071296417Sdimcmddestroy(int gargc __unused, char **gargv) 1072296417Sdim{ 1073296417Sdim int chip = 0, ctl = 0, err = 0, fd, idx, idx2, state; 1074296417Sdim int chipstart, chipstop, ctrlstart, ctrlstop; 1075296417Sdim struct sim_chip_destroy chip_destroy; 1076296417Sdim 1077296417Sdim err = parse_devstring(gargv[2], &ctl, &chip); 1078249423Sdim 1079249423Sdim if (err) 1080296417Sdim return (EX_USAGE); 1081296417Sdim 1082321369Sdim if (ctl == 0xff) { 1083296417Sdim /* Every chip at every controller */ 1084296417Sdim ctrlstart = chipstart = 0; 1085296417Sdim ctrlstop = MAX_SIM_DEV - 1; 1086296417Sdim chipstop = MAX_CTRL_CS - 1; 1087341825Sdim } else { 1088321369Sdim ctrlstart = ctrlstop = ctl; 1089296417Sdim if (chip == 0xff) { 1090296417Sdim /* Every chip at selected controller */ 1091296417Sdim chipstart = 0; 1092296417Sdim chipstop = MAX_CTRL_CS - 1; 1093296417Sdim } else 1094249423Sdim /* Selected chip at selected controller */ 1095249423Sdim chipstart = chipstop = chip; 1096249423Sdim } 1097341825Sdim debug("CTRLSTART=%d CTRLSTOP=%d CHIPSTART=%d CHIPSTOP=%d\n", 1098341825Sdim ctrlstart, ctrlstop, chipstart, chipstop); 1099341825Sdim for (idx = ctrlstart; idx <= ctrlstop; idx++) { 1100341825Sdim err = is_ctrl_created(idx, &state); 1101341825Sdim if (err) { 1102341825Sdim error("Could not acquire ctrl#%d state. Cannot " 1103341825Sdim "destroy controller.", idx); 1104341825Sdim return (EX_SOFTWARE); 1105341825Sdim } 1106341825Sdim if (state == 0) { 1107341825Sdim continue; 1108341825Sdim } 1109341825Sdim err = is_ctrl_running(idx, &state); 1110341825Sdim if (err) { 1111341825Sdim error(MSG_STATUSACQCTRL, idx); 1112341825Sdim return (EX_SOFTWARE); 1113341825Sdim } 1114341825Sdim if (state != 0) { 1115341825Sdim error(MSG_RUNNING, ctl); 1116341825Sdim return (EX_SOFTWARE); 1117341825Sdim } 1118341825Sdim if (opendev(&fd) != EX_OK) 1119341825Sdim return (EX_OSFILE); 1120341825Sdim 1121341825Sdim for (idx2 = chipstart; idx2 <= chipstop; idx2++) { 1122341825Sdim err = is_chip_created(idx, idx2, &state); 1123341825Sdim if (err) { 1124341825Sdim error(MSG_STATUSACQCTRLCHIP, idx2, idx); 1125341825Sdim continue; 1126341825Sdim } 1127341825Sdim if (state == 0) 1128341825Sdim /* There is no such chip running */ 1129341825Sdim continue; 1130341825Sdim chip_destroy.ctrl_num = idx; 1131341825Sdim chip_destroy.chip_num = idx2; 1132341825Sdim ioctl(fd, NANDSIM_DESTROY_CHIP, 1133341825Sdim &chip_destroy); 1134341825Sdim } 1135341825Sdim /* If chip isn't explicitly specified -- destroy ctrl */ 1136341825Sdim if (chip == 0xff) { 1137341825Sdim err = ioctl(fd, NANDSIM_DESTROY_CTRL, &idx); 1138341825Sdim if (err) { 1139341825Sdim error("Could not destroy ctrl#%d", idx); 1140341825Sdim continue; 1141341825Sdim } 1142341825Sdim } 1143341825Sdim close(fd); 1144341825Sdim } 1145341825Sdim return (err); 1146341825Sdim} 1147341825Sdim 1148341825Sdimint 1149341825Sdimmain(int argc, char **argv) 1150341825Sdim{ 1151341825Sdim struct nandsim_command *cmdopts; 1152341825Sdim int retcode = 0; 1153341825Sdim 1154341825Sdim if (argc < 2) { 1155341825Sdim cmdhelp(argc, argv); 1156341825Sdim retcode = EX_USAGE; 1157309124Sdim } else { 1158309124Sdim cmdopts = getcommand(argv[1]); 1159341825Sdim if (cmdopts != NULL && cmdopts->commandfunc != NULL) { 1160341825Sdim if (checkusage(argc, cmdopts->req_argc, argv) == 1) { 1161341825Sdim /* Print command specific usage */ 1162309124Sdim printf("nandsim %s", cmdopts->usagestring); 1163341825Sdim return (EX_USAGE); 1164341825Sdim } 1165341825Sdim retcode = cmdopts->commandfunc(argc, argv); 1166341825Sdim 1167341825Sdim if (retcode == EX_USAGE) { 1168341825Sdim /* Print command-specific usage */ 1169341825Sdim printf("nandsim %s", cmdopts->usagestring); 1170341825Sdim } else if (retcode == EX_OSFILE) { 1171341825Sdim error("Could not open device file"); 1172341825Sdim } 1173341825Sdim 1174341825Sdim } else { 1175341825Sdim error("Unknown command!"); 1176341825Sdim retcode = EX_USAGE; 1177341825Sdim } 1178341825Sdim } 1179341825Sdim return (retcode); 1180341825Sdim} 1181341825Sdim 1182341825Sdimstatic int 1183341825Sdimcmdhelp(int gargc __unused, char **gargv __unused) 1184341825Sdim{ 1185309124Sdim struct nandsim_command *opts; 1186341825Sdim 1187341825Sdim printf("usage: nandsim <command> [command params] [params]\n\n"); 1188341825Sdim 1189341825Sdim for (opts = commands; (opts != NULL) && 1190341825Sdim (opts->cmd_name != NULL); opts++) 1191341825Sdim printf("nandsim %s", opts->usagestring); 1192341825Sdim 1193341825Sdim printf("\n"); 1194341825Sdim return (EX_OK); 1195341825Sdim} 1196341825Sdim 1197341825Sdimstatic void 1198341825Sdimprintchip(struct sim_chip *chip, uint8_t verbose) 1199341825Sdim{ 1200309124Sdim 1201309124Sdim if (chip->created == 0) 1202309124Sdim return; 1203341825Sdim if (verbose > 0) { 1204341825Sdim printf("\n[Chip info]\n"); 1205309124Sdim printf("num= %d\nctrl_num=%d\ndevice_id=%02x" 1206341825Sdim "\tmanufacturer_id=%02x\ndevice_model=%s\nmanufacturer=" 1207341825Sdim "%s\ncol_addr_cycles=%d\nrow_addr_cycles=%d" 1208341825Sdim "\npage_size=%d\noob_size=%d\npages_per_block=%d\n" 1209341825Sdim "blocks_per_lun=%d\nluns=%d\n\nprog_time=%d\n" 1210341825Sdim "erase_time=%d\nread_time=%d\n" 1211341825Sdim "error_ratio=%d\nwear_level=%d\nwrite_protect=%c\n" 1212341825Sdim "chip_width=%db\n", chip->num, chip->ctrl_num, 1213341825Sdim chip->device_id, chip->manufact_id,chip->device_model, 1214341825Sdim chip->manufacturer, chip->col_addr_cycles, 1215341825Sdim chip->row_addr_cycles, chip->page_size, 1216341825Sdim chip->oob_size, chip->pgs_per_blk, chip->blks_per_lun, 1217341825Sdim chip->luns,chip->prog_time, chip->erase_time, 1218341825Sdim chip->read_time, chip->error_ratio, chip->wear_level, 1219341825Sdim (chip->is_wp == 0) ? 'N':'Y', chip->width); 1220309124Sdim } else { 1221341825Sdim printf("[Chip info]\n"); 1222341825Sdim printf("\tnum=%d\n\tdevice_model=%s\n\tmanufacturer=%s\n" 1223341825Sdim "\tpage_size=%d\n\twrite_protect=%s\n", 1224341825Sdim chip->num, chip->device_model, chip->manufacturer, 1225341825Sdim chip->page_size, (chip->is_wp == 0) ? "NO":"YES"); 1226341825Sdim } 1227341825Sdim} 1228341825Sdim 1229341825Sdimstatic void 1230341825Sdimprintctrl(struct sim_ctrl *ctrl) 1231341825Sdim{ 1232341825Sdim int i; 1233341825Sdim 1234341825Sdim if (ctrl->created == 0) { 1235341825Sdim printf(MSG_NOCTRL "\n", ctrl->num); 1236341825Sdim return; 1237341825Sdim } 1238341825Sdim printf("\n[Controller info]\n"); 1239341825Sdim printf("\trunning: %s\n", ctrl->running ? "yes" : "no"); 1240341825Sdim printf("\tnum cs: %d\n", ctrl->num_cs); 1241341825Sdim printf("\tecc: %d\n", ctrl->ecc); 1242341825Sdim printf("\tlog_filename: %s\n", ctrl->filename); 1243341825Sdim printf("\tecc_layout:"); 1244309124Sdim for (i = 0; i < MAX_ECC_BYTES; i++) { 1245309124Sdim if (ctrl->ecc_layout[i] == 0xffff) 1246309124Sdim break; 1247309124Sdim else 1248353358Sdim printf("%c%d", i%16 ? ' ' : '\n', 1249353358Sdim ctrl->ecc_layout[i]); 1250353358Sdim } 1251353358Sdim printf("\n"); 1252353358Sdim} 1253353358Sdim 1254353358Sdimstatic int 1255353358Sdimis_ctrl_running(int ctrl_no, int *running) 1256353358Sdim{ 1257353358Sdim struct sim_ctrl ctrl; 1258353358Sdim int err, fd; 1259353358Sdim 1260353358Sdim ctrl.num = ctrl_no; 1261353358Sdim if (opendev(&fd) != EX_OK) 1262353358Sdim return (EX_OSFILE); 1263353358Sdim 1264353358Sdim err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); 1265353358Sdim if (err) { 1266353358Sdim error(MSG_STATUSACQCTRL, ctrl_no); 1267341825Sdim close(fd); 1268341825Sdim return (err); 1269341825Sdim } 1270341825Sdim *running = ctrl.running; 1271341825Sdim close(fd); 1272341825Sdim return (0); 1273341825Sdim} 1274341825Sdim 1275341825Sdimstatic int 1276341825Sdimis_ctrl_created(int ctrl_no, int *created) 1277341825Sdim{ 1278341825Sdim struct sim_ctrl ctrl; 1279341825Sdim int err, fd; 1280341825Sdim 1281341825Sdim ctrl.num = ctrl_no; 1282341825Sdim 1283341825Sdim if (opendev(&fd) != EX_OK) 1284341825Sdim return (EX_OSFILE); 1285341825Sdim 1286341825Sdim err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); 1287341825Sdim if (err) { 1288341825Sdim error("Could not acquire conf for ctrl#%d", ctrl_no); 1289341825Sdim close(fd); 1290341825Sdim return (err); 1291341825Sdim } 1292341825Sdim *created = ctrl.created; 1293341825Sdim close(fd); 1294341825Sdim return (0); 1295341825Sdim} 1296341825Sdim 1297341825Sdimstatic int 1298341825Sdimis_chip_created(int ctrl_no, int chip_no, int *created) 1299341825Sdim{ 1300341825Sdim struct sim_chip chip; 1301341825Sdim int err, fd; 1302341825Sdim 1303341825Sdim chip.ctrl_num = ctrl_no; 1304341825Sdim chip.num = chip_no; 1305341825Sdim 1306341825Sdim if (opendev(&fd) != EX_OK) 1307341825Sdim return (EX_OSFILE); 1308341825Sdim 1309341825Sdim err = ioctl(fd, NANDSIM_STATUS_CHIP, &chip); 1310341825Sdim if (err) { 1311341825Sdim error("Could not acquire conf for chip#%d", chip_no); 1312341825Sdim close(fd); 1313341825Sdim return (err); 1314341825Sdim } 1315341825Sdim *created = chip.created; 1316341825Sdim close(fd); 1317341825Sdim return (0); 1318341825Sdim} 1319341825Sdim 1320353358Sdimstatic int 1321353358Sdimassert_chip_connected(int ctrl_no, int chip_no) 1322353358Sdim{ 1323353358Sdim int created, running; 1324353358Sdim 1325353358Sdim if (is_ctrl_created(ctrl_no, &created)) 1326353358Sdim return (0); 1327353358Sdim 1328353358Sdim if (!created) { 1329353358Sdim error(MSG_NOCTRL, ctrl_no); 1330353358Sdim return (0); 1331353358Sdim } 1332353358Sdim 1333353358Sdim if (is_chip_created(ctrl_no, chip_no, &created)) 1334353358Sdim return (0); 1335353358Sdim 1336353358Sdim if (!created) { 1337353358Sdim error(MSG_NOTCONFIGDCTRLCHIP, ctrl_no, chip_no); 1338353358Sdim return (0); 1339353358Sdim } 1340353358Sdim 1341353358Sdim if (is_ctrl_running(ctrl_no, &running)) 1342353358Sdim return (0); 1343341825Sdim 1344341825Sdim if (!running) { 1345341825Sdim error(MSG_NOTRUNNING, ctrl_no); 1346341825Sdim return (0); 1347296417Sdim } 1348296417Sdim 1349296417Sdim return (1); 1350296417Sdim} 1351296417Sdim 1352296417Sdimstatic int 1353296417Sdimprintstats(int ctrlno, int chipno, uint32_t pageno, int cdevd) 1354296417Sdim{ 1355309124Sdim struct page_stat_io pstats; 1356296417Sdim struct block_stat_io bstats; 1357296417Sdim struct chip_param_io cparams; 1358296417Sdim uint32_t blkidx; 1359309124Sdim int err; 1360296417Sdim 1361296417Sdim /* Gather information about chip */ 1362309124Sdim err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); 1363353358Sdim 1364296417Sdim if (err) { 1365296417Sdim error("Could not acquire chip info for chip attached to cs#" 1366296417Sdim "%d, ctrl#%d", chipno, ctrlno); 1367296417Sdim return (EX_SOFTWARE); 1368296417Sdim } 1369344779Sdim 1370344779Sdim blkidx = (pageno / cparams.pages_per_block); 1371344779Sdim bstats.block_num = blkidx; 1372344779Sdim 1373344779Sdim err = ioctl(cdevd, NAND_IO_BLOCK_STAT, &bstats); 1374344779Sdim if (err) { 1375344779Sdim error("Could not acquire block#%d statistics!", blkidx); 1376344779Sdim return (ENXIO); 1377296417Sdim } 1378309124Sdim 1379309124Sdim printf("Block #%d erased: %d\n", blkidx, bstats.block_erased); 1380309124Sdim pstats.page_num = pageno; 1381309124Sdim 1382296417Sdim err = ioctl(cdevd, NAND_IO_PAGE_STAT, &pstats); 1383296417Sdim if (err) { 1384344779Sdim error("Could not acquire page statistics!"); 1385353358Sdim return (ENXIO); 1386353358Sdim } 1387344779Sdim 1388344779Sdim debug("BLOCKIDX = %d PAGENO (REL. TO BLK) = %d\n", blkidx, 1389344779Sdim pstats.page_num); 1390344779Sdim 1391344779Sdim printf("Page#%d : reads:%d writes:%d \n\traw reads:%d raw writes:%d " 1392344779Sdim "\n\tecc_succeeded:%d ecc_corrected:%d ecc_failed:%d\n", 1393344779Sdim pstats.page_num, pstats.page_read, pstats.page_written, 1394344779Sdim pstats.page_raw_read, pstats.page_raw_written, 1395344779Sdim pstats.ecc_succeded, pstats.ecc_corrected, pstats.ecc_failed); 1396344779Sdim return (0); 1397344779Sdim} 1398344779Sdim