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