2 * Copyright (C) 2009-2012 Semihalf
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 * Control application for the NAND simulator.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/errno.h>
35 #include <sys/ioctl.h>
38 #include <sys/types.h>
40 #include <dev/nand/nandsim.h>
41 #include <dev/nand/nand_dev.h>
55 #include "nandsim_cfgparse.h"
57 #define SIMDEVICE "/dev/nandsim.ioctl"
59 #define error(fmt, args...) do { \
60 printf("ERROR: " fmt "\n", ##args); } while (0)
62 #define warn(fmt, args...) do { \
63 printf("WARNING: " fmt "\n", ##args); } while (0)
69 #define debug(fmt, args...) do { \
70 printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0)
72 #define debug(fmt, args...) do {} while(0)
75 #define NANDSIM_RAM_LOG_SIZE 16384
77 #define MSG_NOTRUNNING "Controller#%d is not running.Please start" \
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 "\
86 #define MSG_NOCTRL "Controller#%d is not configured!"
87 #define MSG_NOTCONFIGDCTRLCHIP "Chip connected to ctrl#%d at cs#%d " \
90 typedef int (commandfunc_t)(int , char **);
92 static struct nandsim_command *getcommand(char *);
93 static int parse_devstring(char *, int *, int *);
94 static void printchip(struct sim_chip *, uint8_t);
95 static void printctrl(struct sim_ctrl *);
96 static int opendev(int *);
97 static commandfunc_t cmdstatus;
98 static commandfunc_t cmdconf;
99 static commandfunc_t cmdstart;
100 static commandfunc_t cmdstop;
101 static commandfunc_t cmdmod;
102 static commandfunc_t cmderror;
103 static commandfunc_t cmdbb;
104 static commandfunc_t cmdfreeze;
105 static commandfunc_t cmdlog;
106 static commandfunc_t cmdstats;
107 static commandfunc_t cmddump;
108 static commandfunc_t cmdrestore;
109 static commandfunc_t cmddestroy;
110 static commandfunc_t cmdhelp;
111 static int checkusage(int, int, char **);
112 static int is_chip_created(int, int, int *);
113 static int is_ctrl_created(int, int *);
114 static int is_ctrl_running(int, int *);
115 static int assert_chip_connected(int , int);
116 static int printstats(int, int, uint32_t, int);
118 struct 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 */
125 static struct nandsim_command commands[] = {
126 {"status", cmdstatus, 1,
127 "status <ctl_no|--all|-a> [-v]\n" },
129 "conf <filename>\n" },
130 {"start", cmdstart, 1,
131 "start <ctrl_no>\n" },
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" },
137 "stop <ctrl_no>\n" },
138 {"error", cmderror, 5,
139 "error <ctrl_no:cs_no> <page_num> <column> <length> <pattern>\n" },
141 "bb <ctl_no:cs_no> [blk_num1,blk_num2,..] [-U] [-L]\n" },
142 {"freeze", cmdfreeze, 1,
143 "freeze [ctrl_no]\n" },
145 "log <ctrl_no|--all|-a>\n" },
146 {"stats", cmdstats, 2,
147 "stats <ctrl_no:cs_no> <pagenumber>\n" },
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" },
156 {NULL, NULL, 0, NULL},
160 /* Parse command name, and start appropriate function */
161 static struct nandsim_command*
162 getcommand(char *arg)
164 struct nandsim_command *opts;
166 for (opts = commands; (opts != NULL) &&
167 (opts->cmd_name != NULL); opts++) {
168 if (strcmp(opts->cmd_name, arg) == 0)
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).
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
183 parse_devstring(char *str, int *ctrl, int *cs)
186 unsigned int num = 0;
188 /* Ignore white spaces at the beginning */
189 while (isspace(*str) && (*str != '\0'))
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);
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)
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);
213 tmpstr = (char *)strtok(NULL, ":");
215 if ((tmpstr != NULL) && (*tmpstr != '\0')) {
216 if (convert_arguint(tmpstr, &num) != 0)
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!",
229 /* Empty devstring supplied */
232 debug("CTRL=%d CHIP=%d\n", *ctrl, *cs);
240 *fd = open(SIMDEVICE, O_RDWR);
242 error("Could not open simulator device file (%s)!",
250 opencdev(int *cdevd, int ctrl, int chip)
254 sprintf(fname, "/dev/nandsim%d.%d", ctrl, chip);
255 *cdevd = open(fname, O_RDWR);
263 * Check if given arguments count match requirements. If no, or
264 * --help (-h) flag is specified -- return 1 (print usage)
267 checkusage(int gargc, int argsreqd, char **gargv)
270 if (gargc < argsreqd + 2 || (gargc >= (argsreqd + 2) &&
271 (strcmp(gargv[1], "--help") == 0 ||
272 strcmp(gargv[1], "-h") == 0)))
279 cmdstatus(int gargc, char **gargv)
281 int chip = 0, ctl = 0, err = 0, fd, idx, idx2, start, stop;
283 struct sim_ctrl ctrlconf;
284 struct sim_chip chipconf;
286 err = parse_devstring(gargv[2], &ctl, &chip);
289 } else if (ctl == 0xff) {
290 /* Every controller */
292 stop = MAX_SIM_DEV-1;
294 /* Specified controller only */
299 if (opendev(&fd) != EX_OK)
302 for (idx = 0; idx < gargc; idx ++)
303 if (strcmp(gargv[idx], "-v") == 0 ||
304 strcmp(gargv[idx], "--verbose") == 0)
307 for (idx = start; idx <= stop; idx++) {
309 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrlconf);
312 error(MSG_STATUSACQCTRL, idx);
316 printctrl(&ctrlconf);
318 for (idx2 = 0; idx2 < MAX_CTRL_CS; idx2++) {
320 chipconf.ctrl_num = idx;
322 err = ioctl(fd, NANDSIM_STATUS_CHIP, &chipconf);
325 error(MSG_STATUSACQCTRL, idx);
329 printchip(&chipconf, verbose);
337 cmdconf(int gargc __unused, char **gargv)
341 err = parse_config(gargv[2], SIMDEVICE);
349 cmdstart(int gargc __unused, char **gargv)
351 int chip = 0, ctl = 0, err = 0, fd, running, state;
353 err = parse_devstring(gargv[2], &ctl, &chip);
357 err = is_ctrl_created(ctl, &state);
359 return (EX_SOFTWARE);
360 } else if (state == 0) {
361 error(MSG_NOCTRL, ctl);
362 return (EX_SOFTWARE);
365 err = is_ctrl_running(ctl, &running);
367 return (EX_SOFTWARE);
370 warn(MSG_RUNNING, ctl);
372 if (opendev(&fd) != EX_OK)
375 err = ioctl(fd, NANDSIM_START_CTRL, &ctl);
378 error("Cannot start controller#%d", ctl);
386 cmdstop(int gargc __unused, char **gargv)
388 int chip = 0, ctl = 0, err = 0, fd, running;
390 err = parse_devstring(gargv[2], &ctl, &chip);
394 err = is_ctrl_running(ctl, &running);
396 return (EX_SOFTWARE);
399 error(MSG_NOTRUNNING, ctl);
401 if (opendev(&fd) != EX_OK)
404 err = ioctl(fd, NANDSIM_STOP_CTRL, &ctl);
407 error("Cannot stop controller#%d", ctl);
416 cmdmod(int gargc __unused, char **gargv)
418 int chip, ctl, err = 0, fd = -1, i;
422 if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2],
424 /* Set loglevel (ctrl:chip pair independant) */
425 mods.field = SIM_MOD_LOG_LEVEL;
427 if (convert_arguint(gargv[3], &mods.new_value) != 0)
428 return (EX_SOFTWARE);
430 if (opendev(&fd) != EX_OK)
433 err = ioctl(fd, NANDSIM_MODIFY, &mods);
435 error("simulator parameter %s could not be "
436 "modified !", gargv[3]);
438 return (EX_SOFTWARE);
441 debug("request : loglevel = %d\n", mods.new_value);
447 err = parse_devstring(gargv[2], &ctl, &chip);
451 else if (chip == 0xff) {
452 error(MSG_CTRLCHIPNEEDED);
456 if (!assert_chip_connected(ctl, chip))
457 return (EX_SOFTWARE);
459 if (opendev(&fd) != EX_OK)
462 /* Find out which flags were passed */
463 for (i = 3; i < gargc; i++) {
465 if (convert_arguint(gargv[i + 1], &mods.new_value) != 0)
468 if (strcmp(gargv[i], "--prog-time") == 0 ||
469 strcmp(gargv[i], "-p") == 0) {
471 mods.field = SIM_MOD_PROG_TIME;
472 debug("request : progtime = %d\n", mods.new_value);
474 } else if (strcmp(gargv[i], "--erase-time") == 0 ||
475 strcmp(gargv[i], "-e") == 0) {
477 mods.field = SIM_MOD_ERASE_TIME;
478 debug("request : eraseime = %d\n", mods.new_value);
480 } else if (strcmp(gargv[i], "--read-time") == 0 ||
481 strcmp(gargv[i], "-r") == 0) {
483 mods.field = SIM_MOD_READ_TIME;
484 debug("request : read_time = %d\n", mods.new_value);
486 } else if (strcmp(gargv[i], "--error-ratio") == 0 ||
487 strcmp(gargv[i], "-E") == 0) {
489 mods.field = SIM_MOD_ERROR_RATIO;
490 debug("request : error_ratio = %d\n", mods.new_value);
493 /* Flag not recognized, or nothing specified. */
494 error("Unrecognized flag:%s\n", gargv[i]);
500 mods.chip_num = chip;
503 /* Call appropriate ioctl */
504 err = ioctl(fd, NANDSIM_MODIFY, &mods);
506 error("simulator parameter %s could not be modified! ",
517 cmderror(int gargc __unused, char **gargv)
519 uint32_t page, column, len, pattern;
520 int chip = 0, ctl = 0, err = 0, fd;
521 struct sim_error sim_err;
523 err = parse_devstring(gargv[2], &ctl, &chip);
528 error(MSG_CTRLCHIPNEEDED);
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);
538 if (!assert_chip_connected(ctl, chip))
539 return (EX_SOFTWARE);
541 sim_err.page_num = page;
542 sim_err.column = column;
544 sim_err.pattern = pattern;
545 sim_err.ctrl_num = ctl;
546 sim_err.chip_num = chip;
548 if (opendev(&fd) != EX_OK)
551 err = ioctl(fd, NANDSIM_INJECT_ERROR, &sim_err);
555 error("Could not inject error !");
556 return (EX_SOFTWARE);
562 cmdbb(int gargc, char **gargv)
564 struct sim_block_state bs;
565 struct chip_param_io cparams;
567 int c, cdevd, chip = 0, ctl = 0, err = 0, fd, idx;
568 uint8_t flagL = 0, flagU = 0;
569 int *badblocks = NULL;
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)
576 if (strcmp(gargv[idx], "--unmark") == 0 ||
577 strcmp(gargv[idx], "-U") == 0)
581 if (flagL == 2 || flagU == 2 || flagU == 3)
584 err = parse_devstring(gargv[2], &ctl, &chip);
588 if (chip == 0xff || ctl == 0xff) {
589 error(MSG_CTRLCHIPNEEDED);
596 if (!assert_chip_connected(ctl, chip))
597 return (EX_SOFTWARE);
599 if (opencdev(&cdevd, ctl, chip) != EX_OK)
602 err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams);
604 return (EX_SOFTWARE);
611 if (opendev(&fd) != EX_OK)
616 * Flag -L was specified either after blocklist or was not
619 c = parse_intarray(gargv[3], &badblocks);
621 for (idx = 0; idx < c; idx++) {
622 bs.block_num = badblocks[idx];
623 /* Do not change wearout */
625 bs.state = (flagU == 0) ? NANDSIM_BAD_BLOCK :
628 err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs);
630 error("Could not set bad block(%d) for "
632 badblocks[idx], ctl);
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 */
644 err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs);
646 error("Could not acquire block state");
650 printf("Block#%d: wear count: %d %s\n", blkidx,
652 (bs.state == NANDSIM_BAD_BLOCK) ? "BAD":"GOOD");
660 cmdfreeze(int gargc __unused, char **gargv)
662 int chip = 0, ctl = 0, err = 0, fd, i, start = 0, state, stop = 0;
663 struct sim_ctrl_chip ctrlchip;
665 err = parse_devstring(gargv[2], &ctl, &chip);
670 error("You have to specify at least controller number");
674 if (ctl != 0xff && chip == 0xff) {
676 stop = MAX_CTRL_CS - 1;
682 ctrlchip.ctrl_num = ctl;
684 err = is_ctrl_running(ctl, &state);
686 return (EX_SOFTWARE);
688 error(MSG_NOTRUNNING, ctl);
689 return (EX_SOFTWARE);
692 if (opendev(&fd) != EX_OK)
695 for (i = start; i <= stop; i++) {
696 err = is_chip_created(ctl, i, &state);
698 return (EX_SOFTWARE);
699 else if (state == 0) {
703 ctrlchip.chip_num = i;
704 err = ioctl(fd, NANDSIM_FREEZE, &ctrlchip);
706 error("Could not freeze ctrl#%d chip#%d", ctl, i);
708 return (EX_SOFTWARE);
716 cmdlog(int gargc __unused, char **gargv)
719 int chip = 0, ctl = 0, err = 0, fd, idx, start = 0, stop = 0;
722 err = parse_devstring(gargv[2], &ctl, &chip);
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);
732 memset(logbuf, 0, NANDSIM_RAM_LOG_SIZE);
734 log.len = NANDSIM_RAM_LOG_SIZE;
738 stop = MAX_SIM_DEV-1;
744 if (opendev(&fd) != EX_OK) {
749 /* Print logs for selected controller(s) */
750 for (idx = start; idx <= stop; idx++) {
753 err = ioctl(fd, NANDSIM_PRINT_LOG, &log);
755 error("Could not get log for controller %d!", idx);
759 printf("Logs for controller#%d:\n%s\n", idx, logbuf);
768 cmdstats(int gargc __unused, char **gargv)
770 int cdevd, chip = 0, ctl = 0, err = 0;
773 err = parse_devstring(gargv[2], &ctl, &chip);
779 error(MSG_CTRLCHIPNEEDED);
783 if (convert_arguint(gargv[3], &pageno) != 0)
786 if (!assert_chip_connected(ctl, chip))
787 return (EX_SOFTWARE);
789 if (opencdev(&cdevd, ctl, chip) != EX_OK)
792 err = printstats(ctl, chip, pageno, cdevd);
795 return (EX_SOFTWARE);
802 cmddump(int gargc __unused, char **gargv)
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;
811 err = parse_devstring(gargv[2], &ctl, &chip);
815 if (chip == 0xff || ctl == 0xff) {
816 error(MSG_CTRLCHIPNEEDED);
820 if (!assert_chip_connected(ctl, chip))
821 return (EX_SOFTWARE);
823 if (opencdev(&fd, ctl, chip) != EX_OK)
826 err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams);
828 error("Cannot get parameters for chip %d:%d", ctl, chip);
830 return (EX_SOFTWARE);
835 dump.chip_num = chip;
837 dump.len = cparams.pages_per_block * (cparams.page_size +
840 buf = malloc(dump.len);
842 error("Could not allocate memory!");
843 return (EX_SOFTWARE);
848 dumpfd = open(gargv[3], O_WRONLY | O_CREAT, 0666);
850 error("Cannot create dump file.");
852 return (EX_SOFTWARE);
858 return (EX_SOFTWARE);
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!");
870 return (EX_SOFTWARE);
874 * First loop acquires blocks states and writes them to
877 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
878 bs.block_num = blkidx;
879 err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs);
881 error("Could not get bad block(%d) for "
882 "controller (%d)!", blkidx, ctl);
886 return (EX_SOFTWARE);
889 bwritten = write(dumpfd, &bs, sizeof(bs));
890 if (bwritten != sizeof(bs)) {
891 error("Error writing to dumpfile");
895 return (EX_SOFTWARE);
899 /* Second loop dumps the data */
900 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
901 debug("Block#%d...", blkidx);
902 dump.block_num = blkidx;
904 err = ioctl(fd, NANDSIM_DUMP, &dump);
906 error("Could not dump ctrl#%d chip#%d "
907 "block#%d", ctl, chip, blkidx);
912 bwritten = write(dumpfd, dump.data, dump.len);
913 if (bwritten != dump.len) {
914 error("Error writing to dumpfile");
919 totalwritten += bwritten;
921 printf("%d out of %d B written.\n", totalwritten, dump.len * blkidx);
930 cmdrestore(int gargc __unused, char **gargv)
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;
938 struct chip_param_io cparams, dumpcparams;
940 err = parse_devstring(gargv[2], &ctl, &chip);
943 else if (ctl == 0xff) {
944 error(MSG_CTRLCHIPNEEDED);
948 if (!assert_chip_connected(ctl, chip))
949 return (EX_SOFTWARE);
951 /* Get chip geometry */
952 if (opencdev(&fd, ctl, chip) != EX_OK)
955 err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams);
957 error("Cannot get parameters for chip %d:%d", ctl, chip);
963 /* Obtain dump file size */
965 if (stat(gargv[3], &filestat) != 0) {
966 error("Could not acquire file size! : %s",
971 fsize = filestat.st_size;
972 blksz = cparams.pages_per_block * (cparams.page_size +
975 /* Expected dump file size for chip */
976 expfilesz = cparams.blocks * (blksz + sizeof(bs)) + sizeof(cparams);
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);
984 dumpfd = open(gargv[3], O_RDONLY);
986 error("Could not open dump file!");
990 /* Read chip params saved in dumpfile */
991 read(dumpfd, &dumpcparams, sizeof(dumpcparams));
994 if (bcmp(&dumpcparams, &cparams, sizeof(cparams)) != 0) {
995 error("Supplied dump is created for a chip with different "
996 "chip configuration!");
998 return (EX_SOFTWARE);
1001 if (opendev(&fd) != EX_OK) {
1006 buf = malloc(blksz);
1008 error("Could not allocate memory for block buffer");
1011 return (EX_SOFTWARE);
1014 dump.ctrl_num = ctl;
1015 dump.chip_num = chip;
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");
1025 return (EX_SOFTWARE);
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);
1034 err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs);
1036 error("Could not set bad block(%d) for "
1037 "controller: %d, chip: %d!", blkidx, ctl, chip);
1041 return (EX_SOFTWARE);
1045 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
1047 dump.len = read(dumpfd, buf, blksz);
1049 error("Failed to read block#%d from dumpfile.", blkidx);
1053 dump.block_num = blkidx;
1054 err = ioctl(fd, NANDSIM_RESTORE, &dump);
1056 error("Could not restore block#%d of ctrl#%d chip#%d"
1057 ": %s", blkidx, ctl, chip, strerror(errno));
1071 cmddestroy(int gargc __unused, char **gargv)
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;
1077 err = parse_devstring(gargv[2], &ctl, &chip);
1083 /* Every chip at every controller */
1084 ctrlstart = chipstart = 0;
1085 ctrlstop = MAX_SIM_DEV - 1;
1086 chipstop = MAX_CTRL_CS - 1;
1088 ctrlstart = ctrlstop = ctl;
1090 /* Every chip at selected controller */
1092 chipstop = MAX_CTRL_CS - 1;
1094 /* Selected chip at selected controller */
1095 chipstart = chipstop = chip;
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);
1102 error("Could not acquire ctrl#%d state. Cannot "
1103 "destroy controller.", idx);
1104 return (EX_SOFTWARE);
1109 err = is_ctrl_running(idx, &state);
1111 error(MSG_STATUSACQCTRL, idx);
1112 return (EX_SOFTWARE);
1115 error(MSG_RUNNING, ctl);
1116 return (EX_SOFTWARE);
1118 if (opendev(&fd) != EX_OK)
1121 for (idx2 = chipstart; idx2 <= chipstop; idx2++) {
1122 err = is_chip_created(idx, idx2, &state);
1124 error(MSG_STATUSACQCTRLCHIP, idx2, idx);
1128 /* There is no such chip running */
1130 chip_destroy.ctrl_num = idx;
1131 chip_destroy.chip_num = idx2;
1132 ioctl(fd, NANDSIM_DESTROY_CHIP,
1135 /* If chip isn't explicitly specified -- destroy ctrl */
1137 err = ioctl(fd, NANDSIM_DESTROY_CTRL, &idx);
1139 error("Could not destroy ctrl#%d", idx);
1149 main(int argc, char **argv)
1151 struct nandsim_command *cmdopts;
1155 cmdhelp(argc, argv);
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);
1165 retcode = cmdopts->commandfunc(argc, argv);
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");
1175 error("Unknown command!");
1183 cmdhelp(int gargc __unused, char **gargv __unused)
1185 struct nandsim_command *opts;
1187 printf("usage: nandsim <command> [command params] [params]\n\n");
1189 for (opts = commands; (opts != NULL) &&
1190 (opts->cmd_name != NULL); opts++)
1191 printf("nandsim %s", opts->usagestring);
1198 printchip(struct sim_chip *chip, uint8_t verbose)
1201 if (chip->created == 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);
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");
1230 printctrl(struct sim_ctrl *ctrl)
1234 if (ctrl->created == 0) {
1235 printf(MSG_NOCTRL "\n", ctrl->num);
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)
1248 printf("%c%d", i%16 ? ' ' : '\n',
1249 ctrl->ecc_layout[i]);
1255 is_ctrl_running(int ctrl_no, int *running)
1257 struct sim_ctrl ctrl;
1261 if (opendev(&fd) != EX_OK)
1264 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl);
1266 error(MSG_STATUSACQCTRL, ctrl_no);
1270 *running = ctrl.running;
1276 is_ctrl_created(int ctrl_no, int *created)
1278 struct sim_ctrl ctrl;
1283 if (opendev(&fd) != EX_OK)
1286 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl);
1288 error("Could not acquire conf for ctrl#%d", ctrl_no);
1292 *created = ctrl.created;
1298 is_chip_created(int ctrl_no, int chip_no, int *created)
1300 struct sim_chip chip;
1303 chip.ctrl_num = ctrl_no;
1306 if (opendev(&fd) != EX_OK)
1309 err = ioctl(fd, NANDSIM_STATUS_CHIP, &chip);
1311 error("Could not acquire conf for chip#%d", chip_no);
1315 *created = chip.created;
1321 assert_chip_connected(int ctrl_no, int chip_no)
1323 int created, running;
1325 if (is_ctrl_created(ctrl_no, &created))
1329 error(MSG_NOCTRL, ctrl_no);
1333 if (is_chip_created(ctrl_no, chip_no, &created))
1337 error(MSG_NOTCONFIGDCTRLCHIP, ctrl_no, chip_no);
1341 if (is_ctrl_running(ctrl_no, &running))
1345 error(MSG_NOTRUNNING, ctrl_no);
1353 printstats(int ctrlno, int chipno, uint32_t pageno, int cdevd)
1355 struct page_stat_io pstats;
1356 struct block_stat_io bstats;
1357 struct chip_param_io cparams;
1361 /* Gather information about chip */
1362 err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams);
1365 error("Could not acquire chip info for chip attached to cs#"
1366 "%d, ctrl#%d", chipno, ctrlno);
1367 return (EX_SOFTWARE);
1370 blkidx = (pageno / cparams.pages_per_block);
1371 bstats.block_num = blkidx;
1373 err = ioctl(cdevd, NAND_IO_BLOCK_STAT, &bstats);
1375 error("Could not acquire block#%d statistics!", blkidx);
1379 printf("Block #%d erased: %d\n", blkidx, bstats.block_erased);
1380 pstats.page_num = pageno;
1382 err = ioctl(cdevd, NAND_IO_PAGE_STAT, &pstats);
1384 error("Could not acquire page statistics!");
1388 debug("BLOCKIDX = %d PAGENO (REL. TO BLK) = %d\n", blkidx,
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);