1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 2009-2012 Semihalf 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29/* 30 * Control application for the NAND simulator. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD$"); 35 36#include <sys/errno.h> 37#include <sys/ioctl.h> 38#include <sys/mman.h> 39#include <sys/stat.h> 40#include <sys/types.h> 41 42#include <dev/nand/nandsim.h> 43#include <dev/nand/nand_dev.h> 44 45#include <ctype.h> 46#include <fcntl.h> 47#include <getopt.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#include <stdarg.h> 52#include <unistd.h> 53#include <stdlib.h> 54#include <limits.h> 55#include <sysexits.h> 56 57#include "nandsim_cfgparse.h" 58 59#define SIMDEVICE "/dev/nandsim.ioctl" 60 61#define error(fmt, args...) do { \ 62 printf("ERROR: " fmt "\n", ##args); } while (0) 63 64#define warn(fmt, args...) do { \ 65 printf("WARNING: " fmt "\n", ##args); } while (0) 66 67#define DEBUG 68#undef DEBUG 69 70#ifdef DEBUG 71#define debug(fmt, args...) do { \ 72 printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0) 73#else 74#define debug(fmt, args...) do {} while(0) 75#endif 76 77#define NANDSIM_RAM_LOG_SIZE 16384 78 79#define MSG_NOTRUNNING "Controller#%d is not running.Please start" \ 80 " it first." 81#define MSG_RUNNING "Controller#%d is already running!" 82#define MSG_CTRLCHIPNEEDED "You have to specify ctrl_no:cs_no pair!" 83#define MSG_STATUSACQCTRLCHIP "Could not acquire status for ctrl#%d chip#%d" 84#define MSG_STATUSACQCTRL "Could not acquire status for ctrl#%d" 85#define MSG_NOCHIP "There is no such chip configured (chip#%d "\ 86 "at ctrl#%d)!" 87 88#define MSG_NOCTRL "Controller#%d is not configured!" 89#define MSG_NOTCONFIGDCTRLCHIP "Chip connected to ctrl#%d at cs#%d " \ 90 "is not configured." 91 92typedef int (commandfunc_t)(int , char **); 93 94static struct nandsim_command *getcommand(char *); 95static int parse_devstring(char *, int *, int *); 96static void printchip(struct sim_chip *, uint8_t); 97static void printctrl(struct sim_ctrl *); 98static int opendev(int *); 99static commandfunc_t cmdstatus; 100static commandfunc_t cmdconf; 101static commandfunc_t cmdstart; 102static commandfunc_t cmdstop; 103static commandfunc_t cmdmod; 104static commandfunc_t cmderror; 105static commandfunc_t cmdbb; 106static commandfunc_t cmdfreeze; 107static commandfunc_t cmdlog; 108static commandfunc_t cmdstats; 109static commandfunc_t cmddump; 110static commandfunc_t cmdrestore; 111static commandfunc_t cmddestroy; 112static commandfunc_t cmdhelp; 113static int checkusage(int, int, char **); 114static int is_chip_created(int, int, int *); 115static int is_ctrl_created(int, int *); 116static int is_ctrl_running(int, int *); 117static int assert_chip_connected(int , int); 118static int printstats(int, int, uint32_t, int); 119 120struct nandsim_command { 121 const char *cmd_name; /* Command name */ 122 commandfunc_t *commandfunc; /* Ptr to command function */ 123 uint8_t req_argc; /* Mandatory arguments count */ 124 const char *usagestring; /* Usage string */ 125}; 126 127static struct nandsim_command commands[] = { 128 {"status", cmdstatus, 1, 129 "status <ctl_no|--all|-a> [-v]\n" }, 130 {"conf", cmdconf, 1, 131 "conf <filename>\n" }, 132 {"start", cmdstart, 1, 133 "start <ctrl_no>\n" }, 134 {"mod", cmdmod, 2, 135 "mod [-l <loglevel>] | <ctl_no:cs_no> [-p <prog_time>]\n" 136 "\t[-e <erase_time>] [-r <read_time>]\n" 137 "\t[-E <error_ratio>] | [-h]\n" }, 138 {"stop", cmdstop, 1, 139 "stop <ctrl_no>\n" }, 140 {"error", cmderror, 5, 141 "error <ctrl_no:cs_no> <page_num> <column> <length> <pattern>\n" }, 142 {"bb", cmdbb, 2, 143 "bb <ctl_no:cs_no> [blk_num1,blk_num2,..] [-U] [-L]\n" }, 144 {"freeze", cmdfreeze, 1, 145 "freeze [ctrl_no]\n" }, 146 {"log", cmdlog, 1, 147 "log <ctrl_no|--all|-a>\n" }, 148 {"stats", cmdstats, 2, 149 "stats <ctrl_no:cs_no> <pagenumber>\n" }, 150 {"dump", cmddump, 2, 151 "dump <ctrl_no:cs_no> <filename>\n" }, 152 {"restore", cmdrestore, 2, 153 "restore <ctrl_no:chip_no> <filename>\n" }, 154 {"destroy", cmddestroy, 1, 155 "destroy <ctrl_no[:cs_no]|--all|-a>\n" }, 156 {"help", cmdhelp, 0, 157 "help [-v]" }, 158 {NULL, NULL, 0, NULL}, 159}; 160 161 162/* Parse command name, and start appropriate function */ 163static struct nandsim_command* 164getcommand(char *arg) 165{ 166 struct nandsim_command *opts; 167 168 for (opts = commands; (opts != NULL) && 169 (opts->cmd_name != NULL); opts++) { 170 if (strcmp(opts->cmd_name, arg) == 0) 171 return (opts); 172 } 173 return (NULL); 174} 175 176/* 177 * Parse given string in format <ctrl_no>:<cs_no>, if possible -- set 178 * ctrl and/or cs, and return 0 (success) or 1 (in case of error). 179 * 180 * ctrl == 0xff && chip == 0xff : '--all' flag specified 181 * ctrl != 0xff && chip != 0xff : both ctrl & chip were specified 182 * ctrl != 0xff && chip == 0xff : only ctrl was specified 183 */ 184static int 185parse_devstring(char *str, int *ctrl, int *cs) 186{ 187 char *tmpstr; 188 unsigned int num = 0; 189 190 /* Ignore white spaces at the beginning */ 191 while (isspace(*str) && (*str != '\0')) 192 str++; 193 194 *ctrl = 0xff; 195 *cs = 0xff; 196 if (strcmp(str, "--all") == 0 || 197 strcmp(str, "-a") == 0) { 198 /* If --all or -a is specified, ctl==chip==0xff */ 199 debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); 200 return (0); 201 } 202 /* Separate token and try to convert it to int */ 203 tmpstr = (char *)strtok(str, ":"); 204 if ((tmpstr != NULL) && (*tmpstr != '\0')) { 205 if (convert_arguint(tmpstr, &num) != 0) 206 return (1); 207 208 if (num > MAX_SIM_DEV - 1) { 209 error("Invalid ctrl_no supplied: %s. Valid ctrl_no " 210 "value must lie between 0 and 3!", tmpstr); 211 return (1); 212 } 213 214 *ctrl = num; 215 tmpstr = (char *)strtok(NULL, ":"); 216 217 if ((tmpstr != NULL) && (*tmpstr != '\0')) { 218 if (convert_arguint(tmpstr, &num) != 0) 219 return (1); 220 221 /* Check if chip_no is valid */ 222 if (num > MAX_CTRL_CS - 1) { 223 error("Invalid chip_no supplied: %s. Valid " 224 "chip_no value must lie between 0 and 3!", 225 tmpstr); 226 return (1); 227 } 228 *cs = num; 229 } 230 } else 231 /* Empty devstring supplied */ 232 return (1); 233 234 debug("CTRL=%d CHIP=%d\n", *ctrl, *cs); 235 return (0); 236} 237 238static int 239opendev(int *fd) 240{ 241 242 *fd = open(SIMDEVICE, O_RDWR); 243 if (*fd == -1) { 244 error("Could not open simulator device file (%s)!", 245 SIMDEVICE); 246 return (EX_OSFILE); 247 } 248 return (EX_OK); 249} 250 251static int 252opencdev(int *cdevd, int ctrl, int chip) 253{ 254 char fname[255]; 255 256 sprintf(fname, "/dev/nandsim%d.%d", ctrl, chip); 257 *cdevd = open(fname, O_RDWR); 258 if (*cdevd == -1) 259 return (EX_NOINPUT); 260 261 return (EX_OK); 262} 263 264/* 265 * Check if given arguments count match requirements. If no, or 266 * --help (-h) flag is specified -- return 1 (print usage) 267 */ 268static int 269checkusage(int gargc, int argsreqd, char **gargv) 270{ 271 272 if (gargc < argsreqd + 2 || (gargc >= (argsreqd + 2) && 273 (strcmp(gargv[1], "--help") == 0 || 274 strcmp(gargv[1], "-h") == 0))) 275 return (1); 276 277 return (0); 278} 279 280static int 281cmdstatus(int gargc, char **gargv) 282{ 283 int chip = 0, ctl = 0, err = 0, fd, idx, idx2, start, stop; 284 uint8_t verbose = 0; 285 struct sim_ctrl ctrlconf; 286 struct sim_chip chipconf; 287 288 err = parse_devstring(gargv[2], &ctl, &chip); 289 if (err) { 290 return (EX_USAGE); 291 } else if (ctl == 0xff) { 292 /* Every controller */ 293 start = 0; 294 stop = MAX_SIM_DEV-1; 295 } else { 296 /* Specified controller only */ 297 start = ctl; 298 stop = ctl; 299 } 300 301 if (opendev(&fd) != EX_OK) 302 return (EX_OSFILE); 303 304 for (idx = 0; idx < gargc; idx ++) 305 if (strcmp(gargv[idx], "-v") == 0 || 306 strcmp(gargv[idx], "--verbose") == 0) 307 verbose = 1; 308 309 for (idx = start; idx <= stop; idx++) { 310 ctrlconf.num = idx; 311 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrlconf); 312 if (err) { 313 err = EX_SOFTWARE; 314 error(MSG_STATUSACQCTRL, idx); 315 continue; 316 } 317 318 printctrl(&ctrlconf); 319 320 for (idx2 = 0; idx2 < MAX_CTRL_CS; idx2++) { 321 chipconf.num = idx2; 322 chipconf.ctrl_num = idx; 323 324 err = ioctl(fd, NANDSIM_STATUS_CHIP, &chipconf); 325 if (err) { 326 err = EX_SOFTWARE; 327 error(MSG_STATUSACQCTRL, idx); 328 continue; 329 } 330 331 printchip(&chipconf, verbose); 332 } 333 } 334 close(fd); 335 return (err); 336} 337 338static int 339cmdconf(int gargc __unused, char **gargv) 340{ 341 int err; 342 343 err = parse_config(gargv[2], SIMDEVICE); 344 if (err) 345 return (EX_DATAERR); 346 347 return (EX_OK); 348} 349 350static int 351cmdstart(int gargc __unused, char **gargv) 352{ 353 int chip = 0, ctl = 0, err = 0, fd, running, state; 354 355 err = parse_devstring(gargv[2], &ctl, &chip); 356 if (err) 357 return (EX_USAGE); 358 359 err = is_ctrl_created(ctl, &state); 360 if (err) { 361 return (EX_SOFTWARE); 362 } else if (state == 0) { 363 error(MSG_NOCTRL, ctl); 364 return (EX_SOFTWARE); 365 } 366 367 err = is_ctrl_running(ctl, &running); 368 if (err) 369 return (EX_SOFTWARE); 370 371 if (running) { 372 warn(MSG_RUNNING, ctl); 373 } else { 374 if (opendev(&fd) != EX_OK) 375 return (EX_OSFILE); 376 377 err = ioctl(fd, NANDSIM_START_CTRL, &ctl); 378 close(fd); 379 if (err) { 380 error("Cannot start controller#%d", ctl); 381 err = EX_SOFTWARE; 382 } 383 } 384 return (err); 385} 386 387static int 388cmdstop(int gargc __unused, char **gargv) 389{ 390 int chip = 0, ctl = 0, err = 0, fd, running; 391 392 err = parse_devstring(gargv[2], &ctl, &chip); 393 if (err) 394 return (EX_USAGE); 395 396 err = is_ctrl_running(ctl, &running); 397 if (err) 398 return (EX_SOFTWARE); 399 400 if (!running) { 401 error(MSG_NOTRUNNING, ctl); 402 } else { 403 if (opendev(&fd) != EX_OK) 404 return (EX_OSFILE); 405 406 err = ioctl(fd, NANDSIM_STOP_CTRL, &ctl); 407 close(fd); 408 if (err) { 409 error("Cannot stop controller#%d", ctl); 410 err = EX_SOFTWARE; 411 } 412 } 413 414 return (err); 415} 416 417static int 418cmdmod(int gargc __unused, char **gargv) 419{ 420 int chip, ctl, err = 0, fd = -1, i; 421 struct sim_mod mods; 422 423 if (gargc >= 4) { 424 if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2], 425 "-l") == 0) { 426 /* Set loglevel (ctrl:chip pair independent) */ 427 mods.field = SIM_MOD_LOG_LEVEL; 428 429 if (convert_arguint(gargv[3], &mods.new_value) != 0) 430 return (EX_SOFTWARE); 431 432 if (opendev(&fd) != EX_OK) 433 return (EX_OSFILE); 434 435 err = ioctl(fd, NANDSIM_MODIFY, &mods); 436 if (err) { 437 error("simulator parameter %s could not be " 438 "modified !", gargv[3]); 439 close(fd); 440 return (EX_SOFTWARE); 441 } 442 443 debug("request : loglevel = %d\n", mods.new_value); 444 close(fd); 445 return (EX_OK); 446 } 447 } 448 449 err = parse_devstring(gargv[2], &ctl, &chip); 450 if (err) 451 return (EX_USAGE); 452 453 else if (chip == 0xff) { 454 error(MSG_CTRLCHIPNEEDED); 455 return (EX_USAGE); 456 } 457 458 if (!assert_chip_connected(ctl, chip)) 459 return (EX_SOFTWARE); 460 461 if (opendev(&fd) != EX_OK) 462 return (EX_OSFILE); 463 464 /* Find out which flags were passed */ 465 for (i = 3; i < gargc; i++) { 466 467 if (convert_arguint(gargv[i + 1], &mods.new_value) != 0) 468 continue; 469 470 if (strcmp(gargv[i], "--prog-time") == 0 || 471 strcmp(gargv[i], "-p") == 0) { 472 473 mods.field = SIM_MOD_PROG_TIME; 474 debug("request : progtime = %d\n", mods.new_value); 475 476 } else if (strcmp(gargv[i], "--erase-time") == 0 || 477 strcmp(gargv[i], "-e") == 0) { 478 479 mods.field = SIM_MOD_ERASE_TIME; 480 debug("request : eraseime = %d\n", mods.new_value); 481 482 } else if (strcmp(gargv[i], "--read-time") == 0 || 483 strcmp(gargv[i], "-r") == 0) { 484 485 mods.field = SIM_MOD_READ_TIME; 486 debug("request : read_time = %d\n", mods.new_value); 487 488 } else if (strcmp(gargv[i], "--error-ratio") == 0 || 489 strcmp(gargv[i], "-E") == 0) { 490 491 mods.field = SIM_MOD_ERROR_RATIO; 492 debug("request : error_ratio = %d\n", mods.new_value); 493 494 } else { 495 /* Flag not recognized, or nothing specified. */ 496 error("Unrecognized flag:%s\n", gargv[i]); 497 if (fd >= 0) 498 close(fd); 499 return (EX_USAGE); 500 } 501 502 mods.chip_num = chip; 503 mods.ctrl_num = ctl; 504 505 /* Call appropriate ioctl */ 506 err = ioctl(fd, NANDSIM_MODIFY, &mods); 507 if (err) { 508 error("simulator parameter %s could not be modified! ", 509 gargv[i]); 510 continue; 511 } 512 i++; 513 } 514 close(fd); 515 return (EX_OK); 516} 517 518static int 519cmderror(int gargc __unused, char **gargv) 520{ 521 uint32_t page, column, len, pattern; 522 int chip = 0, ctl = 0, err = 0, fd; 523 struct sim_error sim_err; 524 525 err = parse_devstring(gargv[2], &ctl, &chip); 526 if (err) 527 return (EX_USAGE); 528 529 if (chip == 0xff) { 530 error(MSG_CTRLCHIPNEEDED); 531 return (EX_USAGE); 532 } 533 534 if (convert_arguint(gargv[3], &page) || 535 convert_arguint(gargv[4], &column) || 536 convert_arguint(gargv[5], &len) || 537 convert_arguint(gargv[6], &pattern)) 538 return (EX_SOFTWARE); 539 540 if (!assert_chip_connected(ctl, chip)) 541 return (EX_SOFTWARE); 542 543 sim_err.page_num = page; 544 sim_err.column = column; 545 sim_err.len = len; 546 sim_err.pattern = pattern; 547 sim_err.ctrl_num = ctl; 548 sim_err.chip_num = chip; 549 550 if (opendev(&fd) != EX_OK) 551 return (EX_OSFILE); 552 553 err = ioctl(fd, NANDSIM_INJECT_ERROR, &sim_err); 554 555 close(fd); 556 if (err) { 557 error("Could not inject error !"); 558 return (EX_SOFTWARE); 559 } 560 return (EX_OK); 561} 562 563static int 564cmdbb(int gargc, char **gargv) 565{ 566 struct sim_block_state bs; 567 struct chip_param_io cparams; 568 uint32_t blkidx; 569 int c, cdevd, chip = 0, ctl = 0, err = 0, fd, idx; 570 uint8_t flagL = 0, flagU = 0; 571 int *badblocks = NULL; 572 573 /* Check for --list/-L or --unmark/-U flags */ 574 for (idx = 3; idx < gargc; idx++) { 575 if (strcmp(gargv[idx], "--list") == 0 || 576 strcmp(gargv[idx], "-L") == 0) 577 flagL = idx; 578 if (strcmp(gargv[idx], "--unmark") == 0 || 579 strcmp(gargv[idx], "-U") == 0) 580 flagU = idx; 581 } 582 583 if (flagL == 2 || flagU == 2 || flagU == 3) 584 return (EX_USAGE); 585 586 err = parse_devstring(gargv[2], &ctl, &chip); 587 if (err) { 588 return (EX_USAGE); 589 } 590 if (chip == 0xff || ctl == 0xff) { 591 error(MSG_CTRLCHIPNEEDED); 592 return (EX_USAGE); 593 } 594 595 bs.ctrl_num = ctl; 596 bs.chip_num = chip; 597 598 if (!assert_chip_connected(ctl, chip)) 599 return (EX_SOFTWARE); 600 601 if (opencdev(&cdevd, ctl, chip) != EX_OK) 602 return (EX_OSFILE); 603 604 err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); 605 if (err) 606 return (EX_SOFTWARE); 607 608 close(cdevd); 609 610 bs.ctrl_num = ctl; 611 bs.chip_num = chip; 612 613 if (opendev(&fd) != EX_OK) 614 return (EX_OSFILE); 615 616 if (flagL != 3) { 617 /* 618 * Flag -L was specified either after blocklist or was not 619 * specified at all. 620 */ 621 c = parse_intarray(gargv[3], &badblocks); 622 623 for (idx = 0; idx < c; idx++) { 624 bs.block_num = badblocks[idx]; 625 /* Do not change wearout */ 626 bs.wearout = -1; 627 bs.state = (flagU == 0) ? NANDSIM_BAD_BLOCK : 628 NANDSIM_GOOD_BLOCK; 629 630 err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); 631 if (err) { 632 error("Could not set bad block(%d) for " 633 "controller (%d)!", 634 badblocks[idx], ctl); 635 err = EX_SOFTWARE; 636 break; 637 } 638 } 639 } 640 if (flagL != 0) { 641 /* If flag -L was specified (anywhere) */ 642 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 643 bs.block_num = blkidx; 644 /* Do not change the wearout */ 645 bs.wearout = -1; 646 err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); 647 if (err) { 648 error("Could not acquire block state"); 649 err = EX_SOFTWARE; 650 continue; 651 } 652 printf("Block#%d: wear count: %d %s\n", blkidx, 653 bs.wearout, 654 (bs.state == NANDSIM_BAD_BLOCK) ? "BAD":"GOOD"); 655 } 656 } 657 close(fd); 658 return (err); 659} 660 661static int 662cmdfreeze(int gargc __unused, char **gargv) 663{ 664 int chip = 0, ctl = 0, err = 0, fd, i, start = 0, state, stop = 0; 665 struct sim_ctrl_chip ctrlchip; 666 667 err = parse_devstring(gargv[2], &ctl, &chip); 668 if (err) 669 return (EX_USAGE); 670 671 if (ctl == 0xff) { 672 error("You have to specify at least controller number"); 673 return (EX_USAGE); 674 } 675 676 if (ctl != 0xff && chip == 0xff) { 677 start = 0; 678 stop = MAX_CTRL_CS - 1; 679 } else { 680 start = chip; 681 stop = chip; 682 } 683 684 ctrlchip.ctrl_num = ctl; 685 686 err = is_ctrl_running(ctl, &state); 687 if (err) 688 return (EX_SOFTWARE); 689 if (state == 0) { 690 error(MSG_NOTRUNNING, ctl); 691 return (EX_SOFTWARE); 692 } 693 694 if (opendev(&fd) != EX_OK) 695 return (EX_OSFILE); 696 697 for (i = start; i <= stop; i++) { 698 err = is_chip_created(ctl, i, &state); 699 if (err) 700 return (EX_SOFTWARE); 701 else if (state == 0) { 702 continue; 703 } 704 705 ctrlchip.chip_num = i; 706 err = ioctl(fd, NANDSIM_FREEZE, &ctrlchip); 707 if (err) { 708 error("Could not freeze ctrl#%d chip#%d", ctl, i); 709 close(fd); 710 return (EX_SOFTWARE); 711 } 712 } 713 close(fd); 714 return (EX_OK); 715} 716 717static int 718cmdlog(int gargc __unused, char **gargv) 719{ 720 struct sim_log log; 721 int chip = 0, ctl = 0, err = 0, fd, idx, start = 0, stop = 0; 722 char *logbuf; 723 724 err = parse_devstring(gargv[2], &ctl, &chip); 725 if (err) 726 return (EX_USAGE); 727 728 logbuf = (char *)malloc(sizeof(char) * NANDSIM_RAM_LOG_SIZE); 729 if (logbuf == NULL) { 730 error("Not enough memory to create log buffer"); 731 return (EX_SOFTWARE); 732 } 733 734 memset(logbuf, 0, NANDSIM_RAM_LOG_SIZE); 735 log.log = logbuf; 736 log.len = NANDSIM_RAM_LOG_SIZE; 737 738 if (ctl == 0xff) { 739 start = 0; 740 stop = MAX_SIM_DEV-1; 741 } else { 742 start = ctl; 743 stop = ctl; 744 } 745 746 if (opendev(&fd) != EX_OK) { 747 free(logbuf); 748 return (EX_OSFILE); 749 } 750 751 /* Print logs for selected controller(s) */ 752 for (idx = start; idx <= stop; idx++) { 753 log.ctrl_num = idx; 754 755 err = ioctl(fd, NANDSIM_PRINT_LOG, &log); 756 if (err) { 757 error("Could not get log for controller %d!", idx); 758 continue; 759 } 760 761 printf("Logs for controller#%d:\n%s\n", idx, logbuf); 762 } 763 764 free(logbuf); 765 close(fd); 766 return (EX_OK); 767} 768 769static int 770cmdstats(int gargc __unused, char **gargv) 771{ 772 int cdevd, chip = 0, ctl = 0, err = 0; 773 uint32_t pageno = 0; 774 775 err = parse_devstring(gargv[2], &ctl, &chip); 776 777 if (err) 778 return (EX_USAGE); 779 780 if (chip == 0xff) { 781 error(MSG_CTRLCHIPNEEDED); 782 return (EX_USAGE); 783 } 784 785 if (convert_arguint(gargv[3], &pageno) != 0) 786 return (EX_USAGE); 787 788 if (!assert_chip_connected(ctl, chip)) 789 return (EX_SOFTWARE); 790 791 if (opencdev(&cdevd, ctl, chip) != EX_OK) 792 return (EX_OSFILE); 793 794 err = printstats(ctl, chip, pageno, cdevd); 795 if (err) { 796 close(cdevd); 797 return (EX_SOFTWARE); 798 } 799 close(cdevd); 800 return (EX_OK); 801} 802 803static int 804cmddump(int gargc __unused, char **gargv) 805{ 806 struct sim_dump dump; 807 struct sim_block_state bs; 808 struct chip_param_io cparams; 809 int chip = 0, ctl = 0, err = EX_OK, fd, dumpfd; 810 uint32_t blkidx, bwritten = 0, totalwritten = 0; 811 void *buf; 812 813 err = parse_devstring(gargv[2], &ctl, &chip); 814 if (err) 815 return (EX_USAGE); 816 817 if (chip == 0xff || ctl == 0xff) { 818 error(MSG_CTRLCHIPNEEDED); 819 return (EX_USAGE); 820 } 821 822 if (!assert_chip_connected(ctl, chip)) 823 return (EX_SOFTWARE); 824 825 if (opencdev(&fd, ctl, chip) != EX_OK) 826 return (EX_OSFILE); 827 828 err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); 829 if (err) { 830 error("Cannot get parameters for chip %d:%d", ctl, chip); 831 close(fd); 832 return (EX_SOFTWARE); 833 } 834 close(fd); 835 836 dump.ctrl_num = ctl; 837 dump.chip_num = chip; 838 839 dump.len = cparams.pages_per_block * (cparams.page_size + 840 cparams.oob_size); 841 842 buf = malloc(dump.len); 843 if (buf == NULL) { 844 error("Could not allocate memory!"); 845 return (EX_SOFTWARE); 846 } 847 dump.data = buf; 848 849 errno = 0; 850 dumpfd = open(gargv[3], O_WRONLY | O_CREAT, 0666); 851 if (dumpfd == -1) { 852 error("Cannot create dump file."); 853 free(buf); 854 return (EX_SOFTWARE); 855 } 856 857 if (opendev(&fd)) { 858 close(dumpfd); 859 free(buf); 860 return (EX_SOFTWARE); 861 } 862 863 bs.ctrl_num = ctl; 864 bs.chip_num = chip; 865 866 /* First uint32_t in file shall contain block count */ 867 if (write(dumpfd, &cparams, sizeof(cparams)) < (int)sizeof(cparams)) { 868 error("Error writing to dumpfile!"); 869 close(fd); 870 close(dumpfd); 871 free(buf); 872 return (EX_SOFTWARE); 873 } 874 875 /* 876 * First loop acquires blocks states and writes them to 877 * the dump file. 878 */ 879 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 880 bs.block_num = blkidx; 881 err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs); 882 if (err) { 883 error("Could not get bad block(%d) for " 884 "controller (%d)!", blkidx, ctl); 885 close(fd); 886 close(dumpfd); 887 free(buf); 888 return (EX_SOFTWARE); 889 } 890 891 bwritten = write(dumpfd, &bs, sizeof(bs)); 892 if (bwritten != sizeof(bs)) { 893 error("Error writing to dumpfile"); 894 close(fd); 895 close(dumpfd); 896 free(buf); 897 return (EX_SOFTWARE); 898 } 899 } 900 901 /* Second loop dumps the data */ 902 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 903 debug("Block#%d...", blkidx); 904 dump.block_num = blkidx; 905 906 err = ioctl(fd, NANDSIM_DUMP, &dump); 907 if (err) { 908 error("Could not dump ctrl#%d chip#%d " 909 "block#%d", ctl, chip, blkidx); 910 err = EX_SOFTWARE; 911 break; 912 } 913 914 bwritten = write(dumpfd, dump.data, dump.len); 915 if (bwritten != dump.len) { 916 error("Error writing to dumpfile"); 917 err = EX_SOFTWARE; 918 break; 919 } 920 debug("OK!\n"); 921 totalwritten += bwritten; 922 } 923 printf("%d out of %d B written.\n", totalwritten, dump.len * blkidx); 924 925 close(fd); 926 close(dumpfd); 927 free(buf); 928 return (err); 929} 930 931static int 932cmdrestore(int gargc __unused, char **gargv) 933{ 934 struct sim_dump dump; 935 struct sim_block_state bs; 936 struct stat filestat; 937 int chip = 0, ctl = 0, err = 0, fd, dumpfd = -1; 938 uint32_t blkidx, blksz, fsize = 0, expfilesz; 939 void *buf; 940 struct chip_param_io cparams, dumpcparams; 941 942 err = parse_devstring(gargv[2], &ctl, &chip); 943 if (err) 944 return (EX_USAGE); 945 else if (ctl == 0xff) { 946 error(MSG_CTRLCHIPNEEDED); 947 return (EX_USAGE); 948 } 949 950 if (!assert_chip_connected(ctl, chip)) 951 return (EX_SOFTWARE); 952 953 /* Get chip geometry */ 954 if (opencdev(&fd, ctl, chip) != EX_OK) 955 return (EX_OSFILE); 956 957 err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams); 958 if (err) { 959 error("Cannot get parameters for chip %d:%d", ctl, chip); 960 close(fd); 961 return (err); 962 } 963 close(fd); 964 965 /* Obtain dump file size */ 966 errno = 0; 967 if (stat(gargv[3], &filestat) != 0) { 968 error("Could not acquire file size! : %s", 969 strerror(errno)); 970 return (EX_IOERR); 971 } 972 973 fsize = filestat.st_size; 974 blksz = cparams.pages_per_block * (cparams.page_size + 975 cparams.oob_size); 976 977 /* Expected dump file size for chip */ 978 expfilesz = cparams.blocks * (blksz + sizeof(bs)) + sizeof(cparams); 979 980 if (fsize != expfilesz) { 981 error("File size does not match chip geometry (file size: %d" 982 ", dump size: %d)", fsize, expfilesz); 983 return (EX_SOFTWARE); 984 } 985 986 dumpfd = open(gargv[3], O_RDONLY); 987 if (dumpfd == -1) { 988 error("Could not open dump file!"); 989 return (EX_IOERR); 990 } 991 992 /* Read chip params saved in dumpfile */ 993 read(dumpfd, &dumpcparams, sizeof(dumpcparams)); 994 995 /* XXX */ 996 if (bcmp(&dumpcparams, &cparams, sizeof(cparams)) != 0) { 997 error("Supplied dump is created for a chip with different " 998 "chip configuration!"); 999 close(dumpfd); 1000 return (EX_SOFTWARE); 1001 } 1002 1003 if (opendev(&fd) != EX_OK) { 1004 close(dumpfd); 1005 return (EX_OSFILE); 1006 } 1007 1008 buf = malloc(blksz); 1009 if (buf == NULL) { 1010 error("Could not allocate memory for block buffer"); 1011 close(dumpfd); 1012 close(fd); 1013 return (EX_SOFTWARE); 1014 } 1015 1016 dump.ctrl_num = ctl; 1017 dump.chip_num = chip; 1018 dump.data = buf; 1019 /* Restore block states and wearouts */ 1020 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 1021 dump.block_num = blkidx; 1022 if (read(dumpfd, &bs, sizeof(bs)) != sizeof(bs)) { 1023 error("Error reading dumpfile"); 1024 close(dumpfd); 1025 close(fd); 1026 free(buf); 1027 return (EX_SOFTWARE); 1028 } 1029 bs.ctrl_num = ctl; 1030 bs.chip_num = chip; 1031 debug("BLKIDX=%d BLOCKS=%d CTRL=%d CHIP=%d STATE=%d\n" 1032 "WEAROUT=%d BS.CTRL_NUM=%d BS.CHIP_NUM=%d\n", 1033 blkidx, cparams.blocks, dump.ctrl_num, dump.chip_num, 1034 bs.state, bs.wearout, bs.ctrl_num, bs.chip_num); 1035 1036 err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs); 1037 if (err) { 1038 error("Could not set bad block(%d) for " 1039 "controller: %d, chip: %d!", blkidx, ctl, chip); 1040 close(dumpfd); 1041 close(fd); 1042 free(buf); 1043 return (EX_SOFTWARE); 1044 } 1045 } 1046 /* Restore data */ 1047 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) { 1048 errno = 0; 1049 dump.len = read(dumpfd, buf, blksz); 1050 if (errno) { 1051 error("Failed to read block#%d from dumpfile.", blkidx); 1052 err = EX_SOFTWARE; 1053 break; 1054 } 1055 dump.block_num = blkidx; 1056 err = ioctl(fd, NANDSIM_RESTORE, &dump); 1057 if (err) { 1058 error("Could not restore block#%d of ctrl#%d chip#%d" 1059 ": %s", blkidx, ctl, chip, strerror(errno)); 1060 err = EX_SOFTWARE; 1061 break; 1062 } 1063 } 1064 1065 free(buf); 1066 close(dumpfd); 1067 close(fd); 1068 return (err); 1069 1070} 1071 1072static int 1073cmddestroy(int gargc __unused, char **gargv) 1074{ 1075 int chip = 0, ctl = 0, err = 0, fd, idx, idx2, state; 1076 int chipstart, chipstop, ctrlstart, ctrlstop; 1077 struct sim_chip_destroy chip_destroy; 1078 1079 err = parse_devstring(gargv[2], &ctl, &chip); 1080 1081 if (err) 1082 return (EX_USAGE); 1083 1084 if (ctl == 0xff) { 1085 /* Every chip at every controller */ 1086 ctrlstart = chipstart = 0; 1087 ctrlstop = MAX_SIM_DEV - 1; 1088 chipstop = MAX_CTRL_CS - 1; 1089 } else { 1090 ctrlstart = ctrlstop = ctl; 1091 if (chip == 0xff) { 1092 /* Every chip at selected controller */ 1093 chipstart = 0; 1094 chipstop = MAX_CTRL_CS - 1; 1095 } else 1096 /* Selected chip at selected controller */ 1097 chipstart = chipstop = chip; 1098 } 1099 debug("CTRLSTART=%d CTRLSTOP=%d CHIPSTART=%d CHIPSTOP=%d\n", 1100 ctrlstart, ctrlstop, chipstart, chipstop); 1101 for (idx = ctrlstart; idx <= ctrlstop; idx++) { 1102 err = is_ctrl_created(idx, &state); 1103 if (err) { 1104 error("Could not acquire ctrl#%d state. Cannot " 1105 "destroy controller.", idx); 1106 return (EX_SOFTWARE); 1107 } 1108 if (state == 0) { 1109 continue; 1110 } 1111 err = is_ctrl_running(idx, &state); 1112 if (err) { 1113 error(MSG_STATUSACQCTRL, idx); 1114 return (EX_SOFTWARE); 1115 } 1116 if (state != 0) { 1117 error(MSG_RUNNING, ctl); 1118 return (EX_SOFTWARE); 1119 } 1120 if (opendev(&fd) != EX_OK) 1121 return (EX_OSFILE); 1122 1123 for (idx2 = chipstart; idx2 <= chipstop; idx2++) { 1124 err = is_chip_created(idx, idx2, &state); 1125 if (err) { 1126 error(MSG_STATUSACQCTRLCHIP, idx2, idx); 1127 continue; 1128 } 1129 if (state == 0) 1130 /* There is no such chip running */ 1131 continue; 1132 chip_destroy.ctrl_num = idx; 1133 chip_destroy.chip_num = idx2; 1134 ioctl(fd, NANDSIM_DESTROY_CHIP, 1135 &chip_destroy); 1136 } 1137 /* If chip isn't explicitly specified -- destroy ctrl */ 1138 if (chip == 0xff) { 1139 err = ioctl(fd, NANDSIM_DESTROY_CTRL, &idx); 1140 if (err) { 1141 error("Could not destroy ctrl#%d", idx); 1142 continue; 1143 } 1144 } 1145 close(fd); 1146 } 1147 return (err); 1148} 1149 1150int 1151main(int argc, char **argv) 1152{ 1153 struct nandsim_command *cmdopts; 1154 int retcode = 0; 1155 1156 if (argc < 2) { 1157 cmdhelp(argc, argv); 1158 retcode = EX_USAGE; 1159 } else { 1160 cmdopts = getcommand(argv[1]); 1161 if (cmdopts != NULL && cmdopts->commandfunc != NULL) { 1162 if (checkusage(argc, cmdopts->req_argc, argv) == 1) { 1163 /* Print command specific usage */ 1164 printf("nandsim %s", cmdopts->usagestring); 1165 return (EX_USAGE); 1166 } 1167 retcode = cmdopts->commandfunc(argc, argv); 1168 1169 if (retcode == EX_USAGE) { 1170 /* Print command-specific usage */ 1171 printf("nandsim %s", cmdopts->usagestring); 1172 } else if (retcode == EX_OSFILE) { 1173 error("Could not open device file"); 1174 } 1175 1176 } else { 1177 error("Unknown command!"); 1178 retcode = EX_USAGE; 1179 } 1180 } 1181 return (retcode); 1182} 1183 1184static int 1185cmdhelp(int gargc __unused, char **gargv __unused) 1186{ 1187 struct nandsim_command *opts; 1188 1189 printf("usage: nandsim <command> [command params] [params]\n\n"); 1190 1191 for (opts = commands; (opts != NULL) && 1192 (opts->cmd_name != NULL); opts++) 1193 printf("nandsim %s", opts->usagestring); 1194 1195 printf("\n"); 1196 return (EX_OK); 1197} 1198 1199static void 1200printchip(struct sim_chip *chip, uint8_t verbose) 1201{ 1202 1203 if (chip->created == 0) 1204 return; 1205 if (verbose > 0) { 1206 printf("\n[Chip info]\n"); 1207 printf("num= %d\nctrl_num=%d\ndevice_id=%02x" 1208 "\tmanufacturer_id=%02x\ndevice_model=%s\nmanufacturer=" 1209 "%s\ncol_addr_cycles=%d\nrow_addr_cycles=%d" 1210 "\npage_size=%d\noob_size=%d\npages_per_block=%d\n" 1211 "blocks_per_lun=%d\nluns=%d\n\nprog_time=%d\n" 1212 "erase_time=%d\nread_time=%d\n" 1213 "error_ratio=%d\nwear_level=%d\nwrite_protect=%c\n" 1214 "chip_width=%db\n", chip->num, chip->ctrl_num, 1215 chip->device_id, chip->manufact_id,chip->device_model, 1216 chip->manufacturer, chip->col_addr_cycles, 1217 chip->row_addr_cycles, chip->page_size, 1218 chip->oob_size, chip->pgs_per_blk, chip->blks_per_lun, 1219 chip->luns,chip->prog_time, chip->erase_time, 1220 chip->read_time, chip->error_ratio, chip->wear_level, 1221 (chip->is_wp == 0) ? 'N':'Y', chip->width); 1222 } else { 1223 printf("[Chip info]\n"); 1224 printf("\tnum=%d\n\tdevice_model=%s\n\tmanufacturer=%s\n" 1225 "\tpage_size=%d\n\twrite_protect=%s\n", 1226 chip->num, chip->device_model, chip->manufacturer, 1227 chip->page_size, (chip->is_wp == 0) ? "NO":"YES"); 1228 } 1229} 1230 1231static void 1232printctrl(struct sim_ctrl *ctrl) 1233{ 1234 int i; 1235 1236 if (ctrl->created == 0) { 1237 printf(MSG_NOCTRL "\n", ctrl->num); 1238 return; 1239 } 1240 printf("\n[Controller info]\n"); 1241 printf("\trunning: %s\n", ctrl->running ? "yes" : "no"); 1242 printf("\tnum cs: %d\n", ctrl->num_cs); 1243 printf("\tecc: %d\n", ctrl->ecc); 1244 printf("\tlog_filename: %s\n", ctrl->filename); 1245 printf("\tecc_layout:"); 1246 for (i = 0; i < MAX_ECC_BYTES; i++) { 1247 if (ctrl->ecc_layout[i] == 0xffff) 1248 break; 1249 else 1250 printf("%c%d", i%16 ? ' ' : '\n', 1251 ctrl->ecc_layout[i]); 1252 } 1253 printf("\n"); 1254} 1255 1256static int 1257is_ctrl_running(int ctrl_no, int *running) 1258{ 1259 struct sim_ctrl ctrl; 1260 int err, fd; 1261 1262 ctrl.num = ctrl_no; 1263 if (opendev(&fd) != EX_OK) 1264 return (EX_OSFILE); 1265 1266 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); 1267 if (err) { 1268 error(MSG_STATUSACQCTRL, ctrl_no); 1269 close(fd); 1270 return (err); 1271 } 1272 *running = ctrl.running; 1273 close(fd); 1274 return (0); 1275} 1276 1277static int 1278is_ctrl_created(int ctrl_no, int *created) 1279{ 1280 struct sim_ctrl ctrl; 1281 int err, fd; 1282 1283 ctrl.num = ctrl_no; 1284 1285 if (opendev(&fd) != EX_OK) 1286 return (EX_OSFILE); 1287 1288 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl); 1289 if (err) { 1290 error("Could not acquire conf for ctrl#%d", ctrl_no); 1291 close(fd); 1292 return (err); 1293 } 1294 *created = ctrl.created; 1295 close(fd); 1296 return (0); 1297} 1298 1299static int 1300is_chip_created(int ctrl_no, int chip_no, int *created) 1301{ 1302 struct sim_chip chip; 1303 int err, fd; 1304 1305 chip.ctrl_num = ctrl_no; 1306 chip.num = chip_no; 1307 1308 if (opendev(&fd) != EX_OK) 1309 return (EX_OSFILE); 1310 1311 err = ioctl(fd, NANDSIM_STATUS_CHIP, &chip); 1312 if (err) { 1313 error("Could not acquire conf for chip#%d", chip_no); 1314 close(fd); 1315 return (err); 1316 } 1317 *created = chip.created; 1318 close(fd); 1319 return (0); 1320} 1321 1322static int 1323assert_chip_connected(int ctrl_no, int chip_no) 1324{ 1325 int created, running; 1326 1327 if (is_ctrl_created(ctrl_no, &created)) 1328 return (0); 1329 1330 if (!created) { 1331 error(MSG_NOCTRL, ctrl_no); 1332 return (0); 1333 } 1334 1335 if (is_chip_created(ctrl_no, chip_no, &created)) 1336 return (0); 1337 1338 if (!created) { 1339 error(MSG_NOTCONFIGDCTRLCHIP, ctrl_no, chip_no); 1340 return (0); 1341 } 1342 1343 if (is_ctrl_running(ctrl_no, &running)) 1344 return (0); 1345 1346 if (!running) { 1347 error(MSG_NOTRUNNING, ctrl_no); 1348 return (0); 1349 } 1350 1351 return (1); 1352} 1353 1354static int 1355printstats(int ctrlno, int chipno, uint32_t pageno, int cdevd) 1356{ 1357 struct page_stat_io pstats; 1358 struct block_stat_io bstats; 1359 struct chip_param_io cparams; 1360 uint32_t blkidx; 1361 int err; 1362 1363 /* Gather information about chip */ 1364 err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams); 1365 1366 if (err) { 1367 error("Could not acquire chip info for chip attached to cs#" 1368 "%d, ctrl#%d", chipno, ctrlno); 1369 return (EX_SOFTWARE); 1370 } 1371 1372 blkidx = (pageno / cparams.pages_per_block); 1373 bstats.block_num = blkidx; 1374 1375 err = ioctl(cdevd, NAND_IO_BLOCK_STAT, &bstats); 1376 if (err) { 1377 error("Could not acquire block#%d statistics!", blkidx); 1378 return (ENXIO); 1379 } 1380 1381 printf("Block #%d erased: %d\n", blkidx, bstats.block_erased); 1382 pstats.page_num = pageno; 1383 1384 err = ioctl(cdevd, NAND_IO_PAGE_STAT, &pstats); 1385 if (err) { 1386 error("Could not acquire page statistics!"); 1387 return (ENXIO); 1388 } 1389 1390 debug("BLOCKIDX = %d PAGENO (REL. TO BLK) = %d\n", blkidx, 1391 pstats.page_num); 1392 1393 printf("Page#%d : reads:%d writes:%d \n\traw reads:%d raw writes:%d " 1394 "\n\tecc_succeeded:%d ecc_corrected:%d ecc_failed:%d\n", 1395 pstats.page_num, pstats.page_read, pstats.page_written, 1396 pstats.page_raw_read, pstats.page_raw_written, 1397 pstats.ecc_succeded, pstats.ecc_corrected, pstats.ecc_failed); 1398 return (0); 1399} 1400