Example #1
0
static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size)
{
#ifdef CONFIG_CMD_MTDPARTS
	struct mtd_device *dev;
	struct part_info *part;
	u8 pnum;
	int ret;

	ret = mtdparts_init();
	if (ret)
		return ret;

	ret = find_dev_and_part(partname, &dev, &pnum, &part);
	if (ret)
		return ret;

	if (dev->id->type != MTD_DEV_TYPE_NAND) {
		puts("not a NAND device\n");
		return -1;
	}

	*off = part->offset;
	*size = part->size;
	*idx = dev->id->num;

	ret = set_dev(*idx);
	if (ret)
		return ret;

	return 0;
#else
	puts("offset is not a number\n");
	return -1;
#endif
}
Example #2
0
int
sgen_next(sgen **xsg)
{
	sgen	*sg = *xsg;
	int	good, done;
	int	i;

	done = 0;
	i = sg->dev;

	do {
		if (sg->instance) {
			if (sg->ptable) {
				do {
					sg->param += 1;
				} while (sg->param < sg->max_param
					&& !set_param(sg));
			} else {
				sg->max_param = -1;
			}

			if (sg->param < sg->max_param) {
				done = 1;
			} else if (!sg->is_instparam) {
				/* Try instance parameters now */
				sg->is_instparam = 1;
				sg->param = -1;
				sg->max_param =
					*DEVices[i]->DEVpublic.numInstanceParms;
				sg->ptable =
					DEVices[i]->DEVpublic.instanceParms;
			} else {
				sg->is_principle = 0;
				sg->instance->GENnextInstance =
					sg->next_instance;
				sg->instance->GENstate = sg->istate;
				sg->instance = NULL;
			}

		} else if (sg->model) {

			/* Find the first/next good instance for this model */
			for (good = 0; !good && sg->next_instance;
				good = set_inst(sg))
			{
				sg->instance = sg->next_instance;
				sg->next_instance =
					sg->instance->GENnextInstance;
			}


			if (good) {
				sg->is_principle = 0;
				sg->istate = sg->instance->GENstate;
				sg->instance->GENnextInstance = NULL;
				sg->model->GENinstances = sg->instance;
				if (DEVices[i]->DEVpublic.modelParms) {
					sg->max_param =
						*DEVices[i]->DEVpublic.
						numModelParms;
					sg->ptable =
						DEVices[i]->DEVpublic.
						modelParms;
				} else {
					sg->ptable = NULL;
				}
				sg->param = -1;
				sg->is_instparam = 0;
			} else {
				/* No good instances of this model */
				sg->model->GENinstances = sg->first_instance;
				sg->model->GENnextModel = sg->next_model;
				sg->model = NULL;
			}

		} else if (i >= 0) {

			/* Find the first/next good model for this device */
			for (good = 0; !good && sg->next_model;
				good = set_model(sg))
			{
				sg->model = sg->next_model;
				sg->next_model = sg->model->GENnextModel;
			}

			if (good) {
				sg->model->GENnextModel = NULL;
				sg->devlist[i] = sg->model;
				if (DEVices[i]->DEVpublic.modelParms) {
					sg->max_param =
						*DEVices[i]->DEVpublic.
						numModelParms;
					sg->ptable =
						DEVices[i]->DEVpublic.
						modelParms;
				} else {
					sg->ptable = NULL;
				}
				sg->next_instance = sg->first_instance
					= sg->model->GENinstances;
			} else {
				/* No more good models for this device */
				sg->devlist[i] = sg->first_model;
				i = -1; /* Try the next good device */
			}

		} else if (i < DEVmaxnum && sg->dev < DEVmaxnum) {

			/* Find the next good device in this circuit */

			do
				sg->dev++;
			while (sg->dev < DEVmaxnum && sg->devlist[sg->dev]
				&& !set_dev(sg));

			i = sg->dev;

			if (i >= DEVmaxnum) /* PN: Segafult if not = */
				done = 1;
			sg->first_model = sg->next_model = (i<DEVmaxnum) ? sg->devlist[i] : NULL;

		} else {
			done = 1;
		}

	} while (!done);

	if (sg->dev >= DEVmaxnum) {
		FREE(sg);
		*xsg = NULL;
	}
	return 1;
}
Example #3
0
static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count,
			int read)
{
	int ret = 0;

	while (count--) {
		/* Raw access */
		mtd_oob_ops_t ops = {
			.datbuf = (u8 *)addr,
			.oobbuf = ((u8 *)addr) + nand->writesize,
			.len = nand->writesize,
			.ooblen = nand->oobsize,
			.mode = MTD_OOB_RAW
		};

		if (read)
			ret = nand->read_oob(nand, off, &ops);
		else
			ret = nand->write_oob(nand, off, &ops);

		if (ret) {
			printf("%s: error at offset %llx, ret %d\n",
				__func__, (long long)off, ret);
			break;
		}

		addr += nand->writesize + nand->oobsize;
		off += nand->writesize;
	}

	return ret;
}

int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int i, ret = 0;
	ulong addr;
	loff_t off, size, maxsize;
	char *cmd, *s;
	nand_info_t *nand;
#ifdef CONFIG_SYS_NAND_QUIET
	int quiet = CONFIG_SYS_NAND_QUIET;
#else
	int quiet = 0;
#endif
	const char *quiet_str = getenv("quiet");
	int dev = nand_curr_device;
	int repeat = flag & CMD_FLAG_REPEAT;

	/* at least two arguments please */
	if (argc < 2)
		goto usage;

	if (quiet_str)
		quiet = simple_strtoul(quiet_str, NULL, 0) != 0;

	cmd = argv[1];

	/* Only "dump" is repeatable. */
	if (repeat && strcmp(cmd, "dump"))
		return 0;

	if (strcmp(cmd, "info") == 0) {

		putc('\n');
		for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
			if (nand_info[i].name)
				nand_print_and_set_info(i);
		}
		return 0;
	}

	if (strcmp(cmd, "device") == 0) {
		if (argc < 3) {
			putc('\n');
			if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
				puts("no devices available\n");
			else
				nand_print_and_set_info(dev);
			return 0;
		}

		dev = (int)simple_strtoul(argv[2], NULL, 10);
		set_dev(dev);

		return 0;
	}

#ifdef CONFIG_ENV_OFFSET_OOB
	/* this command operates only on the first nand device */
	if (strcmp(cmd, "env.oob") == 0)
		return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
#endif

	/* The following commands operate on the current device, unless
	 * overridden by a partition specifier.  Note that if somehow the
	 * current device is invalid, it will have to be changed to a valid
	 * one before these commands can run, even if a partition specifier
	 * for another device is to be used.
	 */
	if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
	    !nand_info[dev].name) {
		puts("\nno devices available\n");
		return 1;
	}
	nand = &nand_info[dev];

	if (strcmp(cmd, "bad") == 0) {
		printf("\nDevice %d bad blocks:\n", dev);
		for (off = 0; off < nand->size; off += nand->erasesize)
			if (nand_block_isbad(nand, off))
				printf("  %08llx\n", (unsigned long long)off);
		return 0;
	}

	/*
	 * Syntax is:
	 *   0    1     2       3    4
	 *   nand erase [clean] [off size]
	 */
	if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
		nand_erase_options_t opts;
		/* "clean" at index 2 means request to write cleanmarker */
		int clean = argc > 2 && !strcmp("clean", argv[2]);
		int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
		int o = (clean || scrub_yes) ? 3 : 2;
		int scrub = !strncmp(cmd, "scrub", 5);
		int spread = 0;
		int args = 2;
		const char *scrub_warn =
			"Warning: "
			"scrub option will erase all factory set bad blocks!\n"
			"         "
			"There is no reliable way to recover them.\n"
			"         "
			"Use this command only for testing purposes if you\n"
			"         "
			"are sure of what you are doing!\n"
			"\nReally scrub this NAND flash? <y/N>\n";

		if (cmd[5] != 0) {
			if (!strcmp(&cmd[5], ".spread")) {
				spread = 1;
			} else if (!strcmp(&cmd[5], ".part")) {
				args = 1;
			} else if (!strcmp(&cmd[5], ".chip")) {
				args = 0;
			} else {
				goto usage;
			}
		}

		/*
		 * Don't allow missing arguments to cause full chip/partition
		 * erases -- easy to do accidentally, e.g. with a misspelled
		 * variable name.
		 */
		if (argc != o + args)
			goto usage;

		printf("\nNAND %s: ", cmd);
		/* skip first two or three arguments, look for offset and size */
		if (arg_off_size(argc - o, argv + o, &dev, &off, &size,
					&maxsize) != 0)
			return 1;

		nand = &nand_info[dev];

		memset(&opts, 0, sizeof(opts));
		opts.offset = off;
		opts.length = size;
		opts.jffs2  = clean;
		opts.quiet  = quiet;
		opts.spread = spread;

		if (scrub) {
			if (!scrub_yes)
				puts(scrub_warn);

			if (scrub_yes)
				opts.scrub = 1;
			else if (getc() == 'y') {
				puts("y");
				if (getc() == '\r')
					opts.scrub = 1;
				else {
					puts("scrub aborted\n");
					return -1;
				}
			} else {
				puts("scrub aborted\n");
				return -1;
			}
		}
		ret = nand_erase_opts(nand, &opts);
		printf("%s\n", ret ? "ERROR" : "OK");

		return ret == 0 ? 0 : 1;
	}

	if (strncmp(cmd, "dump", 4) == 0) {
		if (argc < 3)
			goto usage;

		off = (int)simple_strtoul(argv[2], NULL, 16);
		ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat);

		return ret == 0 ? 1 : 0;
	}

	if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
		size_t rwsize;
		ulong pagecount = 1;
		int read;
		int raw;

		if (argc < 4)
			goto usage;

		addr = (ulong)simple_strtoul(argv[2], NULL, 16);

		read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
		printf("\nNAND %s: ", read ? "read" : "write");

		nand = &nand_info[dev];

		s = strchr(cmd, '.');

		if (s && !strcmp(s, ".raw")) {
			raw = 1;

			if (arg_off(argv[3], &dev, &off, &size, &maxsize))
				return 1;

			if (argc > 4 && !str2long(argv[4], &pagecount)) {
				printf("'%s' is not a number\n", argv[4]);
				return 1;
			}

			if (pagecount * nand->writesize > size) {
				puts("Size exceeds partition or device limit\n");
				return -1;
			}

			rwsize = pagecount * (nand->writesize + nand->oobsize);
		} else {
			if (arg_off_size(argc - 3, argv + 3, &dev,
						&off, &size, &maxsize) != 0)
				return 1;

			rwsize = size;
		}

		if (!s || !strcmp(s, ".jffs2") ||
		    !strcmp(s, ".e") || !strcmp(s, ".i")) {
			if (read)
				ret = nand_read_skip_bad(nand, off, &rwsize,
							 NULL, maxsize,
							 (u_char *)addr);
			else
				ret = nand_write_skip_bad(nand, off, &rwsize,
							  NULL, maxsize,
							  (u_char *)addr, 0);
#ifdef CONFIG_CMD_NAND_TRIMFFS
		} else if (!strcmp(s, ".trimffs")) {
			if (read) {
				printf("Unknown nand command suffix '%s'\n", s);
				return 1;
			}
			ret = nand_write_skip_bad(nand, off, &rwsize, NULL,
						maxsize, (u_char *)addr,
						WITH_DROP_FFS);
#endif
#ifdef CONFIG_CMD_NAND_YAFFS
		} else if (!strcmp(s, ".yaffs")) {
			if (read) {
				printf("Unknown nand command suffix '%s'.\n", s);
				return 1;
			}
			ret = nand_write_skip_bad(nand, off, &rwsize, NULL,
						maxsize, (u_char *)addr,
						WITH_YAFFS_OOB);
#endif
		} else if (!strcmp(s, ".oob")) {
			/* out-of-band data */
			mtd_oob_ops_t ops = {
				.oobbuf = (u8 *)addr,
				.ooblen = rwsize,
				.mode = MTD_OOB_RAW
			};

			if (read)
				ret = nand->read_oob(nand, off, &ops);
			else
				ret = nand->write_oob(nand, off, &ops);
		} else if (raw) {
Example #4
0
int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
{
	int ret;
	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
	nand_info_t *nand = &nand_info[0];
	char *cmd = argv[1];

	if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !nand->name) {
		puts("no devices available\n");
		return 1;
	}

	set_dev(0);

	if (!strcmp(cmd, "get")) {
		ret = get_nand_env_oob(nand, &nand_env_oob_offset);
		if (ret)
			return 1;

		printf("0x%08lx\n", nand_env_oob_offset);
	} else if (!strcmp(cmd, "set")) {
		loff_t addr;
		loff_t maxsize;
		struct mtd_oob_ops ops;
		int idx = 0;

		if (argc < 3)
			goto usage;

		/* We don't care about size, or maxsize. */
		if (arg_off(argv[2], &idx, &addr, &maxsize, &maxsize)) {
			puts("Offset or partition name expected\n");
			return 1;
		}

		if (idx != 0) {
			puts("Partition not on first NAND device\n");
			return 1;
		}

		if (nand->oobavail < ENV_OFFSET_SIZE) {
			printf("Insufficient available OOB bytes:\n"
			       "%d OOB bytes available but %d required for "
			       "env.oob support\n",
			       nand->oobavail, ENV_OFFSET_SIZE);
			return 1;
		}

		if ((addr & (nand->erasesize - 1)) != 0) {
			printf("Environment offset must be block-aligned\n");
			return 1;
		}

		ops.datbuf = NULL;
		ops.mode = MTD_OOB_AUTO;
		ops.ooboffs = 0;
		ops.ooblen = ENV_OFFSET_SIZE;
		ops.oobbuf = (void *) oob_buf;

		oob_buf[0] = ENV_OOB_MARKER;
		oob_buf[1] = addr / nand->erasesize;

		ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops);
		if (ret) {
			printf("Error writing OOB block 0\n");
			return ret;
		}

		ret = get_nand_env_oob(nand, &nand_env_oob_offset);
		if (ret) {
			printf("Error reading env offset in OOB\n");
			return ret;
		}

		if (addr != nand_env_oob_offset) {
			printf("Verification of env offset in OOB failed: "
			       "0x%08llx expected but got 0x%08lx\n",
			       (unsigned long long)addr, nand_env_oob_offset);
			return 1;
		}
	} else {
		goto usage;
	}

	return ret;

usage:
	return CMD_RET_USAGE;
}
Example #5
0
int
main(int ac, char *av[])
{
	int             ch, res, rv, nread;
	size_t		b_size = MIN_SIZE;
	char            *buf, chb[READB_LEN];
	fd_set          fd_s;

	(void) setlocale(LC_TIME, "");

	if (isatty(std_out))
		opt_interactive = 1;
	else
		opt_interactive = 0;


	while ((ch = getopt(ac, av, "Wciotnf:")) != -1)
		switch (ch) {
		case 'W':
			opt_write = 1;
			break;
		case 'c':
			opt_reconn_close = 1;
			break;
		case 'i':
			opt_interactive = 1;
			break;
		case 'o':
			opt_reconn_oflow = 1;
			break;
		case 't':
			opt_timestamp = 1;
			break;
		case 'n':
			opt_no_switch = 1;
			break;
		case 'f':
			opt_snpdev = optarg;
			break;
		case '?':
		default:
			usage();
		}

	if (modfind("snp") == -1)
		if (kldload("snp") == -1 || modfind("snp") == -1)
			warn("snp module not available");

	signal(SIGINT, cleanup);

	snp_io = open_snp();
	setup_scr();

	if (*(av += optind) == NULL) {
		if (opt_interactive && !opt_no_switch)
			ask_dev(dev_name, MSG_INIT);
		else
			fatal(EX_DATAERR, "no device name given");
	} else
		strncpy(dev_name, *av, DEV_NAME_LEN);

	set_dev(dev_name);

	if (!(buf = (char *) malloc(b_size)))
		fatal(EX_UNAVAILABLE, "malloc failed");

	FD_ZERO(&fd_s);

	while (1) {
		if (opt_interactive)
			FD_SET(std_in, &fd_s);
		FD_SET(snp_io, &fd_s);
		res = select(snp_io + 1, &fd_s, NULL, NULL, NULL);
		if (opt_interactive && FD_ISSET(std_in, &fd_s)) {

			if ((res = ioctl(std_in, FIONREAD, &nread)) != 0)
				fatal(EX_OSERR, "ioctl(FIONREAD)");
			if (nread > READB_LEN)
				nread = READB_LEN;
			rv = read(std_in, chb, nread);
			if (rv == -1 || rv != nread)
				fatal(EX_IOERR, "read (stdin) failed");

			switch (chb[0]) {
			case CHR_CLEAR:
				clear();
				break;
			case CHR_SWITCH:
				if (!opt_no_switch) {
					detach_snp();
					ask_dev(dev_name, MSG_CHANGE);
					set_dev(dev_name);
					break;
				}
			default:
				if (opt_write) {
					rv = write(snp_io, chb, nread);
					if (rv == -1 || rv != nread) {
						detach_snp();
						if (opt_no_switch)
							fatal(EX_IOERR,
							  "write failed");
						ask_dev(dev_name, MSG_NOWRITE);
						set_dev(dev_name);
					}
				}

			}
		}
		if (!FD_ISSET(snp_io, &fd_s))
			continue;

		if ((res = ioctl(snp_io, FIONREAD, &nread)) != 0)
			fatal(EX_OSERR, "ioctl(FIONREAD)");

		switch (nread) {
		case SNP_OFLOW:
			if (opt_reconn_oflow)
				attach_snp();
			else if (opt_interactive && !opt_no_switch) {
				ask_dev(dev_name, MSG_OFLOW);
				set_dev(dev_name);
			} else
				cleanup(-1);
			break;
		case SNP_DETACH:
		case SNP_TTYCLOSE:
			if (opt_reconn_close)
				attach_snp();
			else if (opt_interactive && !opt_no_switch) {
				ask_dev(dev_name, MSG_CLOSED);
				set_dev(dev_name);
			} else
				cleanup(-1);
			break;
		default:
			if (nread < (b_size / 2) && (b_size / 2) > MIN_SIZE) {
				free(buf);
				if (!(buf = (char *) malloc(b_size / 2)))
					fatal(EX_UNAVAILABLE, "malloc failed");
				b_size = b_size / 2;
			}
			if (nread > b_size) {
				b_size = (nread % 2) ? (nread + 1) : (nread);
				free(buf);
				if (!(buf = (char *) malloc(b_size)))
					fatal(EX_UNAVAILABLE, "malloc failed");
			}
			rv = read(snp_io, buf, nread);
			if (rv == -1 || rv != nread)
				fatal(EX_IOERR, "read failed");
			rv = write(std_out, buf, nread);
			if (rv == -1 || rv != nread)
				fatal(EX_IOERR, "write failed");
		}
	}			/* While */
	return(0);
}