2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2009-2012 Semihalf
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
30 * Control application for the NAND simulator.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/errno.h>
37 #include <sys/ioctl.h>
40 #include <sys/types.h>
42 #include <dev/nand/nandsim.h>
43 #include <dev/nand/nand_dev.h>
57 #include "nandsim_cfgparse.h"
59 #define SIMDEVICE "/dev/nandsim.ioctl"
61 #define error(fmt, args...) do { \
62 printf("ERROR: " fmt "\n", ##args); } while (0)
64 #define warn(fmt, args...) do { \
65 printf("WARNING: " fmt "\n", ##args); } while (0)
71 #define debug(fmt, args...) do { \
72 printf("NANDSIM_CONF:" fmt "\n", ##args); } while (0)
74 #define debug(fmt, args...) do {} while(0)
77 #define NANDSIM_RAM_LOG_SIZE 16384
79 #define MSG_NOTRUNNING "Controller#%d is not running.Please start" \
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 "\
88 #define MSG_NOCTRL "Controller#%d is not configured!"
89 #define MSG_NOTCONFIGDCTRLCHIP "Chip connected to ctrl#%d at cs#%d " \
92 typedef int (commandfunc_t)(int , char **);
94 static struct nandsim_command *getcommand(char *);
95 static int parse_devstring(char *, int *, int *);
96 static void printchip(struct sim_chip *, uint8_t);
97 static void printctrl(struct sim_ctrl *);
98 static int opendev(int *);
99 static commandfunc_t cmdstatus;
100 static commandfunc_t cmdconf;
101 static commandfunc_t cmdstart;
102 static commandfunc_t cmdstop;
103 static commandfunc_t cmdmod;
104 static commandfunc_t cmderror;
105 static commandfunc_t cmdbb;
106 static commandfunc_t cmdfreeze;
107 static commandfunc_t cmdlog;
108 static commandfunc_t cmdstats;
109 static commandfunc_t cmddump;
110 static commandfunc_t cmdrestore;
111 static commandfunc_t cmddestroy;
112 static commandfunc_t cmdhelp;
113 static int checkusage(int, int, char **);
114 static int is_chip_created(int, int, int *);
115 static int is_ctrl_created(int, int *);
116 static int is_ctrl_running(int, int *);
117 static int assert_chip_connected(int , int);
118 static int printstats(int, int, uint32_t, int);
120 struct 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 */
127 static struct nandsim_command commands[] = {
128 {"status", cmdstatus, 1,
129 "status <ctl_no|--all|-a> [-v]\n" },
131 "conf <filename>\n" },
132 {"start", cmdstart, 1,
133 "start <ctrl_no>\n" },
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" },
139 "stop <ctrl_no>\n" },
140 {"error", cmderror, 5,
141 "error <ctrl_no:cs_no> <page_num> <column> <length> <pattern>\n" },
143 "bb <ctl_no:cs_no> [blk_num1,blk_num2,..] [-U] [-L]\n" },
144 {"freeze", cmdfreeze, 1,
145 "freeze [ctrl_no]\n" },
147 "log <ctrl_no|--all|-a>\n" },
148 {"stats", cmdstats, 2,
149 "stats <ctrl_no:cs_no> <pagenumber>\n" },
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" },
158 {NULL, NULL, 0, NULL},
162 /* Parse command name, and start appropriate function */
163 static struct nandsim_command*
164 getcommand(char *arg)
166 struct nandsim_command *opts;
168 for (opts = commands; (opts != NULL) &&
169 (opts->cmd_name != NULL); opts++) {
170 if (strcmp(opts->cmd_name, arg) == 0)
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).
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
185 parse_devstring(char *str, int *ctrl, int *cs)
188 unsigned int num = 0;
190 /* Ignore white spaces at the beginning */
191 while (isspace(*str) && (*str != '\0'))
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);
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)
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);
215 tmpstr = (char *)strtok(NULL, ":");
217 if ((tmpstr != NULL) && (*tmpstr != '\0')) {
218 if (convert_arguint(tmpstr, &num) != 0)
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!",
231 /* Empty devstring supplied */
234 debug("CTRL=%d CHIP=%d\n", *ctrl, *cs);
242 *fd = open(SIMDEVICE, O_RDWR);
244 error("Could not open simulator device file (%s)!",
252 opencdev(int *cdevd, int ctrl, int chip)
256 sprintf(fname, "/dev/nandsim%d.%d", ctrl, chip);
257 *cdevd = open(fname, O_RDWR);
265 * Check if given arguments count match requirements. If no, or
266 * --help (-h) flag is specified -- return 1 (print usage)
269 checkusage(int gargc, int argsreqd, char **gargv)
272 if (gargc < argsreqd + 2 || (gargc >= (argsreqd + 2) &&
273 (strcmp(gargv[1], "--help") == 0 ||
274 strcmp(gargv[1], "-h") == 0)))
281 cmdstatus(int gargc, char **gargv)
283 int chip = 0, ctl = 0, err = 0, fd, idx, idx2, start, stop;
285 struct sim_ctrl ctrlconf;
286 struct sim_chip chipconf;
288 err = parse_devstring(gargv[2], &ctl, &chip);
291 } else if (ctl == 0xff) {
292 /* Every controller */
294 stop = MAX_SIM_DEV-1;
296 /* Specified controller only */
301 if (opendev(&fd) != EX_OK)
304 for (idx = 0; idx < gargc; idx ++)
305 if (strcmp(gargv[idx], "-v") == 0 ||
306 strcmp(gargv[idx], "--verbose") == 0)
309 for (idx = start; idx <= stop; idx++) {
311 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrlconf);
314 error(MSG_STATUSACQCTRL, idx);
318 printctrl(&ctrlconf);
320 for (idx2 = 0; idx2 < MAX_CTRL_CS; idx2++) {
322 chipconf.ctrl_num = idx;
324 err = ioctl(fd, NANDSIM_STATUS_CHIP, &chipconf);
327 error(MSG_STATUSACQCTRL, idx);
331 printchip(&chipconf, verbose);
339 cmdconf(int gargc __unused, char **gargv)
343 err = parse_config(gargv[2], SIMDEVICE);
351 cmdstart(int gargc __unused, char **gargv)
353 int chip = 0, ctl = 0, err = 0, fd, running, state;
355 err = parse_devstring(gargv[2], &ctl, &chip);
359 err = is_ctrl_created(ctl, &state);
361 return (EX_SOFTWARE);
362 } else if (state == 0) {
363 error(MSG_NOCTRL, ctl);
364 return (EX_SOFTWARE);
367 err = is_ctrl_running(ctl, &running);
369 return (EX_SOFTWARE);
372 warn(MSG_RUNNING, ctl);
374 if (opendev(&fd) != EX_OK)
377 err = ioctl(fd, NANDSIM_START_CTRL, &ctl);
380 error("Cannot start controller#%d", ctl);
388 cmdstop(int gargc __unused, char **gargv)
390 int chip = 0, ctl = 0, err = 0, fd, running;
392 err = parse_devstring(gargv[2], &ctl, &chip);
396 err = is_ctrl_running(ctl, &running);
398 return (EX_SOFTWARE);
401 error(MSG_NOTRUNNING, ctl);
403 if (opendev(&fd) != EX_OK)
406 err = ioctl(fd, NANDSIM_STOP_CTRL, &ctl);
409 error("Cannot stop controller#%d", ctl);
418 cmdmod(int gargc __unused, char **gargv)
420 int chip, ctl, err = 0, fd = -1, i;
424 if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2],
426 /* Set loglevel (ctrl:chip pair independent) */
427 mods.field = SIM_MOD_LOG_LEVEL;
429 if (convert_arguint(gargv[3], &mods.new_value) != 0)
430 return (EX_SOFTWARE);
432 if (opendev(&fd) != EX_OK)
435 err = ioctl(fd, NANDSIM_MODIFY, &mods);
437 error("simulator parameter %s could not be "
438 "modified !", gargv[3]);
440 return (EX_SOFTWARE);
443 debug("request : loglevel = %d\n", mods.new_value);
449 err = parse_devstring(gargv[2], &ctl, &chip);
453 else if (chip == 0xff) {
454 error(MSG_CTRLCHIPNEEDED);
458 if (!assert_chip_connected(ctl, chip))
459 return (EX_SOFTWARE);
461 if (opendev(&fd) != EX_OK)
464 /* Find out which flags were passed */
465 for (i = 3; i < gargc; i++) {
467 if (convert_arguint(gargv[i + 1], &mods.new_value) != 0)
470 if (strcmp(gargv[i], "--prog-time") == 0 ||
471 strcmp(gargv[i], "-p") == 0) {
473 mods.field = SIM_MOD_PROG_TIME;
474 debug("request : progtime = %d\n", mods.new_value);
476 } else if (strcmp(gargv[i], "--erase-time") == 0 ||
477 strcmp(gargv[i], "-e") == 0) {
479 mods.field = SIM_MOD_ERASE_TIME;
480 debug("request : eraseime = %d\n", mods.new_value);
482 } else if (strcmp(gargv[i], "--read-time") == 0 ||
483 strcmp(gargv[i], "-r") == 0) {
485 mods.field = SIM_MOD_READ_TIME;
486 debug("request : read_time = %d\n", mods.new_value);
488 } else if (strcmp(gargv[i], "--error-ratio") == 0 ||
489 strcmp(gargv[i], "-E") == 0) {
491 mods.field = SIM_MOD_ERROR_RATIO;
492 debug("request : error_ratio = %d\n", mods.new_value);
495 /* Flag not recognized, or nothing specified. */
496 error("Unrecognized flag:%s\n", gargv[i]);
502 mods.chip_num = chip;
505 /* Call appropriate ioctl */
506 err = ioctl(fd, NANDSIM_MODIFY, &mods);
508 error("simulator parameter %s could not be modified! ",
519 cmderror(int gargc __unused, char **gargv)
521 uint32_t page, column, len, pattern;
522 int chip = 0, ctl = 0, err = 0, fd;
523 struct sim_error sim_err;
525 err = parse_devstring(gargv[2], &ctl, &chip);
530 error(MSG_CTRLCHIPNEEDED);
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);
540 if (!assert_chip_connected(ctl, chip))
541 return (EX_SOFTWARE);
543 sim_err.page_num = page;
544 sim_err.column = column;
546 sim_err.pattern = pattern;
547 sim_err.ctrl_num = ctl;
548 sim_err.chip_num = chip;
550 if (opendev(&fd) != EX_OK)
553 err = ioctl(fd, NANDSIM_INJECT_ERROR, &sim_err);
557 error("Could not inject error !");
558 return (EX_SOFTWARE);
564 cmdbb(int gargc, char **gargv)
566 struct sim_block_state bs;
567 struct chip_param_io cparams;
569 int c, cdevd, chip = 0, ctl = 0, err = 0, fd, idx;
570 uint8_t flagL = 0, flagU = 0;
571 int *badblocks = NULL;
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)
578 if (strcmp(gargv[idx], "--unmark") == 0 ||
579 strcmp(gargv[idx], "-U") == 0)
583 if (flagL == 2 || flagU == 2 || flagU == 3)
586 err = parse_devstring(gargv[2], &ctl, &chip);
590 if (chip == 0xff || ctl == 0xff) {
591 error(MSG_CTRLCHIPNEEDED);
598 if (!assert_chip_connected(ctl, chip))
599 return (EX_SOFTWARE);
601 if (opencdev(&cdevd, ctl, chip) != EX_OK)
604 err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams);
606 return (EX_SOFTWARE);
613 if (opendev(&fd) != EX_OK)
618 * Flag -L was specified either after blocklist or was not
621 c = parse_intarray(gargv[3], &badblocks);
623 for (idx = 0; idx < c; idx++) {
624 bs.block_num = badblocks[idx];
625 /* Do not change wearout */
627 bs.state = (flagU == 0) ? NANDSIM_BAD_BLOCK :
630 err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs);
632 error("Could not set bad block(%d) for "
634 badblocks[idx], ctl);
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 */
646 err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs);
648 error("Could not acquire block state");
652 printf("Block#%d: wear count: %d %s\n", blkidx,
654 (bs.state == NANDSIM_BAD_BLOCK) ? "BAD":"GOOD");
662 cmdfreeze(int gargc __unused, char **gargv)
664 int chip = 0, ctl = 0, err = 0, fd, i, start = 0, state, stop = 0;
665 struct sim_ctrl_chip ctrlchip;
667 err = parse_devstring(gargv[2], &ctl, &chip);
672 error("You have to specify at least controller number");
676 if (ctl != 0xff && chip == 0xff) {
678 stop = MAX_CTRL_CS - 1;
684 ctrlchip.ctrl_num = ctl;
686 err = is_ctrl_running(ctl, &state);
688 return (EX_SOFTWARE);
690 error(MSG_NOTRUNNING, ctl);
691 return (EX_SOFTWARE);
694 if (opendev(&fd) != EX_OK)
697 for (i = start; i <= stop; i++) {
698 err = is_chip_created(ctl, i, &state);
700 return (EX_SOFTWARE);
701 else if (state == 0) {
705 ctrlchip.chip_num = i;
706 err = ioctl(fd, NANDSIM_FREEZE, &ctrlchip);
708 error("Could not freeze ctrl#%d chip#%d", ctl, i);
710 return (EX_SOFTWARE);
718 cmdlog(int gargc __unused, char **gargv)
721 int chip = 0, ctl = 0, err = 0, fd, idx, start = 0, stop = 0;
724 err = parse_devstring(gargv[2], &ctl, &chip);
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);
734 memset(logbuf, 0, NANDSIM_RAM_LOG_SIZE);
736 log.len = NANDSIM_RAM_LOG_SIZE;
740 stop = MAX_SIM_DEV-1;
746 if (opendev(&fd) != EX_OK) {
751 /* Print logs for selected controller(s) */
752 for (idx = start; idx <= stop; idx++) {
755 err = ioctl(fd, NANDSIM_PRINT_LOG, &log);
757 error("Could not get log for controller %d!", idx);
761 printf("Logs for controller#%d:\n%s\n", idx, logbuf);
770 cmdstats(int gargc __unused, char **gargv)
772 int cdevd, chip = 0, ctl = 0, err = 0;
775 err = parse_devstring(gargv[2], &ctl, &chip);
781 error(MSG_CTRLCHIPNEEDED);
785 if (convert_arguint(gargv[3], &pageno) != 0)
788 if (!assert_chip_connected(ctl, chip))
789 return (EX_SOFTWARE);
791 if (opencdev(&cdevd, ctl, chip) != EX_OK)
794 err = printstats(ctl, chip, pageno, cdevd);
797 return (EX_SOFTWARE);
804 cmddump(int gargc __unused, char **gargv)
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;
813 err = parse_devstring(gargv[2], &ctl, &chip);
817 if (chip == 0xff || ctl == 0xff) {
818 error(MSG_CTRLCHIPNEEDED);
822 if (!assert_chip_connected(ctl, chip))
823 return (EX_SOFTWARE);
825 if (opencdev(&fd, ctl, chip) != EX_OK)
828 err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams);
830 error("Cannot get parameters for chip %d:%d", ctl, chip);
832 return (EX_SOFTWARE);
837 dump.chip_num = chip;
839 dump.len = cparams.pages_per_block * (cparams.page_size +
842 buf = malloc(dump.len);
844 error("Could not allocate memory!");
845 return (EX_SOFTWARE);
850 dumpfd = open(gargv[3], O_WRONLY | O_CREAT, 0666);
852 error("Cannot create dump file.");
854 return (EX_SOFTWARE);
860 return (EX_SOFTWARE);
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!");
872 return (EX_SOFTWARE);
876 * First loop acquires blocks states and writes them to
879 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
880 bs.block_num = blkidx;
881 err = ioctl(fd, NANDSIM_GET_BLOCK_STATE, &bs);
883 error("Could not get bad block(%d) for "
884 "controller (%d)!", blkidx, ctl);
888 return (EX_SOFTWARE);
891 bwritten = write(dumpfd, &bs, sizeof(bs));
892 if (bwritten != sizeof(bs)) {
893 error("Error writing to dumpfile");
897 return (EX_SOFTWARE);
901 /* Second loop dumps the data */
902 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
903 debug("Block#%d...", blkidx);
904 dump.block_num = blkidx;
906 err = ioctl(fd, NANDSIM_DUMP, &dump);
908 error("Could not dump ctrl#%d chip#%d "
909 "block#%d", ctl, chip, blkidx);
914 bwritten = write(dumpfd, dump.data, dump.len);
915 if (bwritten != dump.len) {
916 error("Error writing to dumpfile");
921 totalwritten += bwritten;
923 printf("%d out of %d B written.\n", totalwritten, dump.len * blkidx);
932 cmdrestore(int gargc __unused, char **gargv)
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;
940 struct chip_param_io cparams, dumpcparams;
942 err = parse_devstring(gargv[2], &ctl, &chip);
945 else if (ctl == 0xff) {
946 error(MSG_CTRLCHIPNEEDED);
950 if (!assert_chip_connected(ctl, chip))
951 return (EX_SOFTWARE);
953 /* Get chip geometry */
954 if (opencdev(&fd, ctl, chip) != EX_OK)
957 err = ioctl(fd, NAND_IO_GET_CHIP_PARAM, &cparams);
959 error("Cannot get parameters for chip %d:%d", ctl, chip);
965 /* Obtain dump file size */
967 if (stat(gargv[3], &filestat) != 0) {
968 error("Could not acquire file size! : %s",
973 fsize = filestat.st_size;
974 blksz = cparams.pages_per_block * (cparams.page_size +
977 /* Expected dump file size for chip */
978 expfilesz = cparams.blocks * (blksz + sizeof(bs)) + sizeof(cparams);
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);
986 dumpfd = open(gargv[3], O_RDONLY);
988 error("Could not open dump file!");
992 /* Read chip params saved in dumpfile */
993 read(dumpfd, &dumpcparams, sizeof(dumpcparams));
996 if (bcmp(&dumpcparams, &cparams, sizeof(cparams)) != 0) {
997 error("Supplied dump is created for a chip with different "
998 "chip configuration!");
1000 return (EX_SOFTWARE);
1003 if (opendev(&fd) != EX_OK) {
1008 buf = malloc(blksz);
1010 error("Could not allocate memory for block buffer");
1013 return (EX_SOFTWARE);
1016 dump.ctrl_num = ctl;
1017 dump.chip_num = chip;
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");
1027 return (EX_SOFTWARE);
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);
1036 err = ioctl(fd, NANDSIM_SET_BLOCK_STATE, &bs);
1038 error("Could not set bad block(%d) for "
1039 "controller: %d, chip: %d!", blkidx, ctl, chip);
1043 return (EX_SOFTWARE);
1047 for (blkidx = 0; blkidx < cparams.blocks; blkidx++) {
1049 dump.len = read(dumpfd, buf, blksz);
1051 error("Failed to read block#%d from dumpfile.", blkidx);
1055 dump.block_num = blkidx;
1056 err = ioctl(fd, NANDSIM_RESTORE, &dump);
1058 error("Could not restore block#%d of ctrl#%d chip#%d"
1059 ": %s", blkidx, ctl, chip, strerror(errno));
1073 cmddestroy(int gargc __unused, char **gargv)
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;
1079 err = parse_devstring(gargv[2], &ctl, &chip);
1085 /* Every chip at every controller */
1086 ctrlstart = chipstart = 0;
1087 ctrlstop = MAX_SIM_DEV - 1;
1088 chipstop = MAX_CTRL_CS - 1;
1090 ctrlstart = ctrlstop = ctl;
1092 /* Every chip at selected controller */
1094 chipstop = MAX_CTRL_CS - 1;
1096 /* Selected chip at selected controller */
1097 chipstart = chipstop = chip;
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);
1104 error("Could not acquire ctrl#%d state. Cannot "
1105 "destroy controller.", idx);
1106 return (EX_SOFTWARE);
1111 err = is_ctrl_running(idx, &state);
1113 error(MSG_STATUSACQCTRL, idx);
1114 return (EX_SOFTWARE);
1117 error(MSG_RUNNING, ctl);
1118 return (EX_SOFTWARE);
1120 if (opendev(&fd) != EX_OK)
1123 for (idx2 = chipstart; idx2 <= chipstop; idx2++) {
1124 err = is_chip_created(idx, idx2, &state);
1126 error(MSG_STATUSACQCTRLCHIP, idx2, idx);
1130 /* There is no such chip running */
1132 chip_destroy.ctrl_num = idx;
1133 chip_destroy.chip_num = idx2;
1134 ioctl(fd, NANDSIM_DESTROY_CHIP,
1137 /* If chip isn't explicitly specified -- destroy ctrl */
1139 err = ioctl(fd, NANDSIM_DESTROY_CTRL, &idx);
1141 error("Could not destroy ctrl#%d", idx);
1151 main(int argc, char **argv)
1153 struct nandsim_command *cmdopts;
1157 cmdhelp(argc, argv);
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);
1167 retcode = cmdopts->commandfunc(argc, argv);
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");
1177 error("Unknown command!");
1185 cmdhelp(int gargc __unused, char **gargv __unused)
1187 struct nandsim_command *opts;
1189 printf("usage: nandsim <command> [command params] [params]\n\n");
1191 for (opts = commands; (opts != NULL) &&
1192 (opts->cmd_name != NULL); opts++)
1193 printf("nandsim %s", opts->usagestring);
1200 printchip(struct sim_chip *chip, uint8_t verbose)
1203 if (chip->created == 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);
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");
1232 printctrl(struct sim_ctrl *ctrl)
1236 if (ctrl->created == 0) {
1237 printf(MSG_NOCTRL "\n", ctrl->num);
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)
1250 printf("%c%d", i%16 ? ' ' : '\n',
1251 ctrl->ecc_layout[i]);
1257 is_ctrl_running(int ctrl_no, int *running)
1259 struct sim_ctrl ctrl;
1263 if (opendev(&fd) != EX_OK)
1266 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl);
1268 error(MSG_STATUSACQCTRL, ctrl_no);
1272 *running = ctrl.running;
1278 is_ctrl_created(int ctrl_no, int *created)
1280 struct sim_ctrl ctrl;
1285 if (opendev(&fd) != EX_OK)
1288 err = ioctl(fd, NANDSIM_STATUS_CTRL, &ctrl);
1290 error("Could not acquire conf for ctrl#%d", ctrl_no);
1294 *created = ctrl.created;
1300 is_chip_created(int ctrl_no, int chip_no, int *created)
1302 struct sim_chip chip;
1305 chip.ctrl_num = ctrl_no;
1308 if (opendev(&fd) != EX_OK)
1311 err = ioctl(fd, NANDSIM_STATUS_CHIP, &chip);
1313 error("Could not acquire conf for chip#%d", chip_no);
1317 *created = chip.created;
1323 assert_chip_connected(int ctrl_no, int chip_no)
1325 int created, running;
1327 if (is_ctrl_created(ctrl_no, &created))
1331 error(MSG_NOCTRL, ctrl_no);
1335 if (is_chip_created(ctrl_no, chip_no, &created))
1339 error(MSG_NOTCONFIGDCTRLCHIP, ctrl_no, chip_no);
1343 if (is_ctrl_running(ctrl_no, &running))
1347 error(MSG_NOTRUNNING, ctrl_no);
1355 printstats(int ctrlno, int chipno, uint32_t pageno, int cdevd)
1357 struct page_stat_io pstats;
1358 struct block_stat_io bstats;
1359 struct chip_param_io cparams;
1363 /* Gather information about chip */
1364 err = ioctl(cdevd, NAND_IO_GET_CHIP_PARAM, &cparams);
1367 error("Could not acquire chip info for chip attached to cs#"
1368 "%d, ctrl#%d", chipno, ctrlno);
1369 return (EX_SOFTWARE);
1372 blkidx = (pageno / cparams.pages_per_block);
1373 bstats.block_num = blkidx;
1375 err = ioctl(cdevd, NAND_IO_BLOCK_STAT, &bstats);
1377 error("Could not acquire block#%d statistics!", blkidx);
1381 printf("Block #%d erased: %d\n", blkidx, bstats.block_erased);
1382 pstats.page_num = pageno;
1384 err = ioctl(cdevd, NAND_IO_PAGE_STAT, &pstats);
1386 error("Could not acquire page statistics!");
1390 debug("BLOCKIDX = %d PAGENO (REL. TO BLK) = %d\n", blkidx,
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);