mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* Create and use C API for ubiformat
@ 2016-04-25 11:30 Sascha Hauer
  2016-04-25 11:30 ` [PATCH 1/5] commands: ubiformat: Pass around context data Sascha Hauer
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Sascha Hauer @ 2016-04-25 11:30 UTC (permalink / raw)
  To: Barebox List

The USB fastboot gadget can call ubiformat when necessary. This is done
by executing the "ubiformat" command. This is not so nice since with
this the fastboot gadget needs command support enabled. This series
gets rid of this dependency by creating a C API for ubiformat.

Sascha

----------------------------------------------------------------
Sascha Hauer (5):
      commands: ubiformat: Pass around context data
      commands: ubiformat: create separate function for ubiformat
      commands: ubiformat: move code to common/
      usb: fastboot: Use C API for ubiformat
      usb: fastboot: drop CONFIG_COMMAND_SUPPORT dependency

 commands/Kconfig                |   4 +-
 commands/ubiformat.c            | 686 +++-------------------------------------
 common/Kconfig                  |   7 +
 common/Makefile                 |   1 +
 common/ubiformat.c              | 675 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/Kconfig      |   1 +
 drivers/usb/gadget/f_fastboot.c |  18 +-
 7 files changed, 735 insertions(+), 657 deletions(-)
 create mode 100644 common/ubiformat.c

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] commands: ubiformat: Pass around context data
  2016-04-25 11:30 Create and use C API for ubiformat Sascha Hauer
@ 2016-04-25 11:30 ` Sascha Hauer
  2016-04-25 11:30 ` [PATCH 2/5] commands: ubiformat: create separate function for ubiformat Sascha Hauer
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2016-04-25 11:30 UTC (permalink / raw)
  To: Barebox List

Instead of using a static global context data struct, pass the
data around. This is a first step to create a C API for ubiformat.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 commands/ubiformat.c | 241 ++++++++++++++++++++++++++-------------------------
 1 file changed, 121 insertions(+), 120 deletions(-)

diff --git a/commands/ubiformat.c b/commands/ubiformat.c
index 2ffdd0c..ec5e9d7 100644
--- a/commands/ubiformat.c
+++ b/commands/ubiformat.c
@@ -55,7 +55,7 @@
 #include <mtd/mtd-peb.h>
 
 /* The variables below are set by command line arguments */
-struct args {
+struct ubiformat_args {
 	unsigned int yes:1;
 	unsigned int quiet:1;
 	unsigned int verbose:1;
@@ -71,14 +71,12 @@ struct args {
 	const char *node;
 };
 
-static struct args args;
-
-static int parse_opt(int argc, char *argv[])
+static int parse_opt(int argc, char *argv[], struct ubiformat_args *args)
 {
 	srand(get_time_ns());
-	memset(&args, 0, sizeof(args));
-	args.ubi_ver = 1;
-	args.image_seq = rand();
+	memset(args, 0, sizeof(*args));
+	args->ubi_ver = 1;
+	args->image_seq = rand();
 
 	while (1) {
 		int key;
@@ -90,47 +88,47 @@ static int parse_opt(int argc, char *argv[])
 
 		switch (key) {
 		case 's':
-			args.subpage_size = strtoull_suffix(optarg, NULL, 0);
-			if (args.subpage_size <= 0)
+			args->subpage_size = strtoull_suffix(optarg, NULL, 0);
+			if (args->subpage_size <= 0)
 				return errmsg("bad sub-page size: \"%s\"", optarg);
-			if (!is_power_of_2(args.subpage_size))
+			if (!is_power_of_2(args->subpage_size))
 				return errmsg("sub-page size should be power of 2");
 			break;
 
 		case 'O':
-			args.vid_hdr_offs = simple_strtoul(optarg, NULL, 0);
-			if (args.vid_hdr_offs <= 0)
+			args->vid_hdr_offs = simple_strtoul(optarg, NULL, 0);
+			if (args->vid_hdr_offs <= 0)
 				return errmsg("bad VID header offset: \"%s\"", optarg);
 			break;
 
 		case 'e':
-			args.ec = simple_strtoull(optarg, NULL, 0);
-			if (args.ec < 0)
+			args->ec = simple_strtoull(optarg, NULL, 0);
+			if (args->ec < 0)
 				return errmsg("bad erase counter value: \"%s\"", optarg);
-			if (args.ec >= EC_MAX)
-				return errmsg("too high erase %llu, counter, max is %u", args.ec, EC_MAX);
-			args.override_ec = 1;
+			if (args->ec >= EC_MAX)
+				return errmsg("too high erase %llu, counter, max is %u", args->ec, EC_MAX);
+			args->override_ec = 1;
 			break;
 
 		case 'f':
-			args.image = optarg;
+			args->image = optarg;
 			break;
 
 		case 'n':
-			args.novtbl = 1;
+			args->novtbl = 1;
 			break;
 
 		case 'y':
-			args.yes = 1;
+			args->yes = 1;
 			break;
 
 		case 'q':
-			args.quiet = 1;
+			args->quiet = 1;
 			break;
 
 		case 'x':
-			args.ubi_ver = simple_strtoul(optarg, NULL, 0);
-			if (args.ubi_ver < 0)
+			args->ubi_ver = simple_strtoul(optarg, NULL, 0);
+			if (args->ubi_ver < 0)
 				return errmsg("bad UBI version: \"%s\"", optarg);
 			break;
 
@@ -138,11 +136,11 @@ static int parse_opt(int argc, char *argv[])
 			image_seq = simple_strtoul(optarg, NULL, 0);
 			if (image_seq > 0xFFFFFFFF)
 				return errmsg("bad UBI image sequence number: \"%s\"", optarg);
-			args.image_seq = image_seq;
+			args->image_seq = image_seq;
 			break;
 
 		case 'v':
-			args.verbose = 1;
+			args->verbose = 1;
 			break;
 
 		default:
@@ -150,7 +148,7 @@ static int parse_opt(int argc, char *argv[])
 		}
 	}
 
-	if (args.quiet && args.verbose)
+	if (args->quiet && args->verbose)
 		return errmsg("using \"-q\" and \"-v\" at the same time does not make sense");
 
 	if (optind == argc)
@@ -158,11 +156,11 @@ static int parse_opt(int argc, char *argv[])
 	else if (optind != argc - 1)
 		return errmsg("more then one MTD device specified");
 
-	if (args.image && args.novtbl)
+	if (args->image && args->novtbl)
 		return errmsg("-n cannot be used together with -f");
 
 
-	args.node = argv[optind];
+	args->node = argv[optind];
 	return 0;
 }
 
@@ -227,18 +225,18 @@ static int drop_ffs(struct mtd_info *mtd, const void *buf, int len)
 	return len;
 }
 
-static int open_file(off_t *sz)
+static int open_file(const char *file, off_t *sz)
 {
 	int fd;
 	struct stat st;
 
-	if (stat(args.image, &st))
-		return sys_errmsg("cannot open \"%s\"", args.image);
+	if (stat(file, &st))
+		return sys_errmsg("cannot open \"%s\"", file);
 
 	*sz = st.st_size;
-	fd  = open(args.image, O_RDONLY);
+	fd  = open(file, O_RDONLY);
 	if (fd < 0)
-		return sys_errmsg("cannot open \"%s\"", args.image);
+		return sys_errmsg("cannot open \"%s\"", file);
 
 	return fd;
 }
@@ -247,7 +245,7 @@ static int open_file(off_t *sz)
  * Returns %-1 if consecutive bad blocks exceeds the
  * MAX_CONSECUTIVE_BAD_BLOCKS and returns %0 otherwise.
  */
-static int consecutive_bad_check(int eb)
+static int consecutive_bad_check(struct ubiformat_args *args, int eb)
 {
 	static int consecutive_bad_blocks = 1;
 	static int prev_bb = -1;
@@ -263,7 +261,7 @@ static int consecutive_bad_check(int eb)
 	prev_bb = eb;
 
 	if (consecutive_bad_blocks >= MAX_CONSECUTIVE_BAD_BLOCKS) {
-		if (!args.quiet)
+		if (!args->quiet)
 			printf("\n");
 		return errmsg("consecutive bad blocks exceed limit: %d, bad flash?",
 		              MAX_CONSECUTIVE_BAD_BLOCKS);
@@ -273,15 +271,16 @@ static int consecutive_bad_check(int eb)
 }
 
 /* TODO: we should actually torture the PEB before marking it as bad */
-static int mark_bad(struct mtd_info *mtd, struct ubi_scan_info *si, int eb)
+static int mark_bad(struct ubiformat_args *args, struct mtd_info *mtd,
+		    struct ubi_scan_info *si, int eb)
 {
 	int err;
 
-	if (!args.quiet)
+	if (!args->quiet)
 		normsg_cont("marking block %d bad\n", eb);
 
 	if (!mtd_can_have_bb(mtd)) {
-		if (!args.quiet)
+		if (!args->quiet)
 			printf("\n");
 		return errmsg("bad blocks not supported by this flash");
 	}
@@ -293,10 +292,10 @@ static int mark_bad(struct mtd_info *mtd, struct ubi_scan_info *si, int eb)
 	si->bad_cnt += 1;
 	si->ec[eb] = EB_BAD;
 
-	return consecutive_bad_check(eb);
+	return consecutive_bad_check(args, eb);
 }
 
-static int flash_image(struct mtd_info *mtd,
+static int flash_image(struct ubiformat_args *args, struct mtd_info *mtd,
 		       const struct ubigen_info *ui, struct ubi_scan_info *si)
 {
 	int fd, img_ebs, eb, written_ebs = 0, ret = -1, eb_cnt;
@@ -305,7 +304,7 @@ static int flash_image(struct mtd_info *mtd,
 
 	eb_cnt = mtd_num_pebs(mtd);
 
-	fd = open_file(&st_size);
+	fd = open_file(args->image, &st_size);
 	if (fd < 0)
 		return fd;
 
@@ -319,28 +318,28 @@ static int flash_image(struct mtd_info *mtd,
 
 	if (img_ebs > si->good_cnt) {
 		sys_errmsg("file \"%s\" is too large (%lld bytes)",
-			   args.image, (long long)st_size);
+			   args->image, (long long)st_size);
 		goto out_close;
 	}
 
 	if (st_size % mtd->erasesize) {
 		sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of "
 			   "eraseblock size (%d bytes)",
-			   args.image, (long long)st_size, mtd->erasesize);
+			   args->image, (long long)st_size, mtd->erasesize);
 		goto out_close;
 	}
 
 	if (st_size == 0) {
-		sys_errmsg("file \"%s\" has size 0 bytes", args.image);
+		sys_errmsg("file \"%s\" has size 0 bytes", args->image);
 		goto out_close;
 	}
 
-	verbose(args.verbose, "will write %d eraseblocks", img_ebs);
+	verbose(args->verbose, "will write %d eraseblocks", img_ebs);
 	for (eb = 0; eb < eb_cnt; eb++) {
 		int err, new_len;
 		long long ec;
 
-		if (!args.quiet && !args.verbose) {
+		if (!args->quiet && !args->verbose) {
 			printf("\rubiformat: flashing eraseblock %d -- %2u %% complete  ",
 			       eb, (eb + 1) * 100 / eb_cnt);
 		}
@@ -348,20 +347,20 @@ static int flash_image(struct mtd_info *mtd,
 		if (si->ec[eb] == EB_BAD)
 			continue;
 
-		if (args.verbose) {
+		if (args->verbose) {
 			normsg_cont("eraseblock %d: erase", eb);
 		}
 
 		err = mtd_peb_erase(mtd, eb);
 		if (err) {
-			if (!args.quiet)
+			if (!args->quiet)
 				printf("\n");
 			sys_errmsg("failed to erase eraseblock %d", eb);
 
 			if (err != EIO)
 				goto out_close;
 
-			if (mark_bad(mtd, si, eb))
+			if (mark_bad(args, mtd, si, eb))
 				goto out_close;
 
 			continue;
@@ -370,29 +369,29 @@ static int flash_image(struct mtd_info *mtd,
 		err = read_full(fd, buf, mtd->erasesize);
 		if (err < 0) {
 			sys_errmsg("failed to read eraseblock %d from \"%s\"",
-				   written_ebs, args.image);
+				   written_ebs, args->image);
 			goto out_close;
 		}
 
-		if (args.override_ec)
-			ec = args.ec;
+		if (args->override_ec)
+			ec = args->ec;
 		else if (si->ec[eb] <= EC_MAX)
 			ec = si->ec[eb] + 1;
 		else
 			ec = si->mean_ec;
 
-		if (args.verbose) {
+		if (args->verbose) {
 			printf(", change EC to %lld", ec);
 		}
 
 		err = change_ech((struct ubi_ec_hdr *)buf, ui->image_seq, ec);
 		if (err) {
 			errmsg("bad EC header at eraseblock %d of \"%s\"",
-			       written_ebs, args.image);
+			       written_ebs, args->image);
 			goto out_close;
 		}
 
-		if (args.verbose) {
+		if (args->verbose) {
 			printf(", write data\n");
 		}
 
@@ -408,7 +407,7 @@ static int flash_image(struct mtd_info *mtd,
 			err = mtd_peb_torture(mtd, eb);
 			if (err < 0 && err != -EIO)
 				goto out_close;
-			if (err == -EIO && consecutive_bad_check(eb))
+			if (err == -EIO && consecutive_bad_check(args, eb))
 				goto out_close;
 
 			continue;
@@ -417,7 +416,7 @@ static int flash_image(struct mtd_info *mtd,
 			break;
 	}
 
-	if (!args.quiet && !args.verbose)
+	if (!args->quiet && !args->verbose)
 		printf("\n");
 
 	ret = eb + 1;
@@ -428,9 +427,9 @@ out_close:
 	return ret;
 }
 
-static int format(struct mtd_info *mtd,
+static int format(struct ubiformat_args *args, struct mtd_info *mtd,
 		  const struct ubigen_info *ui, struct ubi_scan_info *si,
-		  int start_eb, int novtbl, int subpage_size)
+		  int start_eb, int novtbl)
 {
 	int eb, err, write_size, eb_cnt;
 	struct ubi_ec_hdr *hdr;
@@ -440,9 +439,9 @@ static int format(struct mtd_info *mtd,
 
 	eb_cnt = mtd_num_pebs(mtd);
 
-	write_size = UBI_EC_HDR_SIZE + subpage_size - 1;
-	write_size /= subpage_size;
-	write_size *= subpage_size;
+	write_size = UBI_EC_HDR_SIZE + args->subpage_size - 1;
+	write_size /= args->subpage_size;
+	write_size *= args->subpage_size;
 	hdr = malloc(write_size);
 	if (!hdr)
 		return sys_errmsg("cannot allocate %d bytes of memory", write_size);
@@ -451,7 +450,7 @@ static int format(struct mtd_info *mtd,
 	for (eb = start_eb; eb < eb_cnt; eb++) {
 		long long ec;
 
-		if (!args.quiet && !args.verbose) {
+		if (!args->quiet && !args->verbose) {
 			printf("\rubiformat: formatting eraseblock %d -- %2u %% complete  ",
 			       eb, (eb + 1 - start_eb) * 100 / (eb_cnt - start_eb));
 		}
@@ -459,28 +458,28 @@ static int format(struct mtd_info *mtd,
 		if (si->ec[eb] == EB_BAD)
 			continue;
 
-		if (args.override_ec)
-			ec = args.ec;
+		if (args->override_ec)
+			ec = args->ec;
 		else if (si->ec[eb] <= EC_MAX)
 			ec = si->ec[eb] + 1;
 		else
 			ec = si->mean_ec;
 		ubigen_init_ec_hdr(ui, hdr, ec);
 
-		if (args.verbose) {
+		if (args->verbose) {
 			normsg_cont("eraseblock %d: erase", eb);
 		}
 
 		err = mtd_peb_erase(mtd, eb);
 		if (err) {
-			if (!args.quiet)
+			if (!args->quiet)
 				printf("\n");
 
 			sys_errmsg("failed to erase eraseblock %d", eb);
 			if (err != EIO)
 				goto out_free;
 
-			if (mark_bad(mtd, si, eb))
+			if (mark_bad(args, mtd, si, eb))
 				goto out_free;
 			continue;
 		}
@@ -493,24 +492,24 @@ static int format(struct mtd_info *mtd,
 				eb2 = eb;
 				ec2 = ec;
 			}
-			if (args.verbose)
+			if (args->verbose)
 				printf(", do not write EC, leave for vtbl\n");
 			continue;
 		}
 
-		if (args.verbose) {
+		if (args->verbose) {
 			printf(", write EC %lld\n", ec);
 		}
 
 		err = mtd_peb_write(mtd, hdr, eb, 0, write_size);
 		if (err) {
-			if (!args.quiet && !args.verbose)
+			if (!args->quiet && !args->verbose)
 				printf("\n");
 			sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d",
 				   write_size, eb);
 
 			if (errno != EIO) {
-				if (args.subpage_size != mtd->writesize)
+				if (args->subpage_size != mtd->writesize)
 					normsg("may be sub-page size is incorrect?");
 				goto out_free;
 			}
@@ -518,7 +517,7 @@ static int format(struct mtd_info *mtd,
 			err = mtd_peb_torture(mtd, eb);
 			if (err < 0 && err != -EIO)
 				goto out_free;
-			if (err == -EIO && consecutive_bad_check(eb))
+			if (err == -EIO && consecutive_bad_check(args, eb))
 				goto out_free;
 
 			continue;
@@ -526,7 +525,7 @@ static int format(struct mtd_info *mtd,
 		}
 	}
 
-	if (!args.quiet && !args.verbose)
+	if (!args->quiet && !args->verbose)
 		printf("\n");
 
 	if (!novtbl) {
@@ -535,7 +534,7 @@ static int format(struct mtd_info *mtd,
 			goto out_free;
 		}
 
-		verbose(args.verbose, "write volume table to eraseblocks %d and %d", eb1, eb2);
+		verbose(args->verbose, "write volume table to eraseblocks %d and %d", eb1, eb2);
 		vtbl = ubigen_create_empty_vtbl(ui);
 		if (!vtbl)
 			goto out_free;
@@ -564,14 +563,16 @@ int do_ubiformat(int argc, char *argv[])
 	struct ubi_scan_info *si;
 	struct mtd_info_user mtd_user;
 	int ubi_num;
+	struct ubiformat_args __args;
+	struct ubiformat_args *args = &__args;
 
-	err = parse_opt(argc, argv);
+	err = parse_opt(argc, argv, args);
 	if (err)
 		return err;
 
-	fd = open(args.node, O_RDWR);
+	fd = open(args->node, O_RDWR);
 	if (fd < 0)
-		return sys_errmsg("cannot open \"%s\"", args.node);
+		return sys_errmsg("cannot open \"%s\"", args->node);
 
 	if (ioctl(fd, MEMGETINFO, &mtd_user)) {
 		sys_errmsg("MEMGETINFO ioctl request failed");
@@ -586,21 +587,21 @@ int do_ubiformat(int argc, char *argv[])
 		goto out_close;
 	}
 
-	if (args.subpage_size) {
-		if (args.subpage_size != mtd->writesize >> mtd->subpage_sft)
-			args.manual_subpage = 1;
+	if (args->subpage_size) {
+		if (args->subpage_size != mtd->writesize >> mtd->subpage_sft)
+			args->manual_subpage = 1;
 	} else {
-		args.subpage_size = mtd->writesize >> mtd->subpage_sft;
+		args->subpage_size = mtd->writesize >> mtd->subpage_sft;
 	}
 
-	if (args.manual_subpage) {
+	if (args->manual_subpage) {
 		/* Do some sanity check */
-		if (args.subpage_size > mtd->writesize) {
+		if (args->subpage_size > mtd->writesize) {
 			errmsg("sub-page cannot be larger than min. I/O unit");
 			goto out_close;
 		}
 
-		if (mtd->writesize % args.subpage_size) {
+		if (mtd->writesize % args->subpage_size) {
 			errmsg("min. I/O unit size should be multiple of "
 			       "sub-page size");
 			goto out_close;
@@ -608,19 +609,19 @@ int do_ubiformat(int argc, char *argv[])
 	}
 
 	/* Validate VID header offset if it was specified */
-	if (args.vid_hdr_offs != 0) {
-		if (args.vid_hdr_offs % 8) {
+	if (args->vid_hdr_offs != 0) {
+		if (args->vid_hdr_offs % 8) {
 			errmsg("VID header offset has to be multiple of min. I/O unit size");
 			goto out_close;
 		}
-		if (args.vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd->erasesize) {
+		if (args->vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd->erasesize) {
 			errmsg("bad VID header offset");
 			goto out_close;
 		}
 	}
 
 	if (!(mtd->flags & MTD_WRITEABLE)) {
-		errmsg("%s is a read-only device", args.node);
+		errmsg("%s is a read-only device", args->node);
 		goto out_close;
 	}
 
@@ -636,23 +637,23 @@ int do_ubiformat(int argc, char *argv[])
 
 	eb_cnt = mtd_div_by_eb(mtd->size, mtd);
 
-	if (!args.quiet) {
-		normsg_cont("%s (%s), size %lld bytes (%s)", args.node, mtd_type_str(mtd),
+	if (!args->quiet) {
+		normsg_cont("%s (%s), size %lld bytes (%s)", args->node, mtd_type_str(mtd),
 			mtd->size, size_human_readable(mtd->size));
 		printf(", %d eraseblocks of %d bytes (%s)", eb_cnt,
 			mtd->erasesize, size_human_readable(mtd->erasesize));
 		printf(", min. I/O size %d bytes\n", mtd->writesize);
 	}
 
-	if (args.quiet)
+	if (args->quiet)
 		verbose = 0;
-	else if (args.verbose)
+	else if (args->verbose)
 		verbose = 2;
 	else
 		verbose = 1;
 	err = libscan_ubi_scan(mtd, &si, verbose);
 	if (err) {
-		errmsg("failed to scan %s", args.node);
+		errmsg("failed to scan %s", args->node);
 		goto out_close;
 	}
 
@@ -661,13 +662,13 @@ int do_ubiformat(int argc, char *argv[])
 		goto out_free;
 	}
 
-	if (si->good_cnt < 2 && (!args.novtbl || args.image)) {
+	if (si->good_cnt < 2 && (!args->novtbl || args->image)) {
 		errmsg("too few non-bad eraseblocks (%d) on %s",
-		       si->good_cnt, args.node);
+		       si->good_cnt, args->node);
 		goto out_free;
 	}
 
-	if (!args.quiet) {
+	if (!args->quiet) {
 		if (si->ok_cnt)
 			normsg("%d eraseblocks have valid erase counter, mean value is %lld",
 			       si->ok_cnt, si->mean_ec);
@@ -679,16 +680,16 @@ int do_ubiformat(int argc, char *argv[])
 	}
 
 	if (si->alien_cnt) {
-		if (!args.quiet)
+		if (!args->quiet)
 			warnmsg("%d of %d eraseblocks contain non-ubifs data",
 				si->alien_cnt, si->good_cnt);
-		if (!args.yes && !args.quiet)
+		if (!args->yes && !args->quiet)
 			warnmsg("use '-y' to force erasing");
-		if (!args.yes)
+		if (!args->yes)
 			goto out_free;
 	}
 
-	if (!args.override_ec && si->empty_cnt < si->good_cnt) {
+	if (!args->override_ec && si->empty_cnt < si->good_cnt) {
 		int percent = (si->ok_cnt * 100) / si->good_cnt;
 
 		/*
@@ -696,10 +697,10 @@ int do_ubiformat(int argc, char *argv[])
 		 * erase counters.
 		 */
 		if (percent < 50) {
-			if (!args.quiet) {
+			if (!args->quiet) {
 				warnmsg("only %d of %d eraseblocks have valid erase counter",
 					si->ok_cnt, si->good_cnt);
-				if (args.yes) {
+				if (args->yes) {
 					normsg("erase counter 0 will be used for all eraseblocks");
 					normsg("note, arbitrary erase counter value may be specified using -e option");
 
@@ -708,43 +709,43 @@ int do_ubiformat(int argc, char *argv[])
 				}
 			}
 
-			if (!args.yes)
+			if (!args->yes)
 				goto out_free;
 
-			args.ec = 0;
-			args.override_ec = 1;
+			args->ec = 0;
+			args->override_ec = 1;
 
 		} else if (percent < 95) {
-			if (!args.quiet) {
+			if (!args->quiet) {
 				warnmsg("only %d of %d eraseblocks have valid erase counter",
 					si->ok_cnt, si->good_cnt);
-				if (args.yes)
+				if (args->yes)
 					normsg("mean erase counter %lld will be used for the rest of eraseblock",
 					       si->mean_ec);
 				else
 					warnmsg("use '-y' to force erase counters");
 			}
 
-			if (!args.yes)
+			if (!args->yes)
 				goto out_free;
 
-			args.ec = si->mean_ec;
-			args.override_ec = 1;
+			args->ec = si->mean_ec;
+			args->override_ec = 1;
 		}
 	}
 
-	if (!args.quiet && args.override_ec)
-		normsg("use erase counter %lld for all eraseblocks", args.ec);
+	if (!args->quiet && args->override_ec)
+		normsg("use erase counter %lld for all eraseblocks", args->ec);
 
-	ubigen_info_init(&ui, mtd->erasesize, mtd->writesize, args.subpage_size,
-			 args.vid_hdr_offs, args.ubi_ver, args.image_seq);
+	ubigen_info_init(&ui, mtd->erasesize, mtd->writesize, args->subpage_size,
+			 args->vid_hdr_offs, args->ubi_ver, args->image_seq);
 
 	if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
 		/*
 		 * Hmm, what we read from flash and what we calculated using
 		 * min. I/O unit size and sub-page size differs.
 		 */
-		if (!args.quiet) {
+		if (!args->quiet) {
 			warnmsg("VID header and data offsets on flash are %d and %d, "
 				"which is different to requested offsets %d and %d",
 				si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs,
@@ -753,16 +754,16 @@ int do_ubiformat(int argc, char *argv[])
 		}
 	}
 
-	if (args.image) {
-		err = flash_image(mtd, &ui, si);
+	if (args->image) {
+		err = flash_image(args, mtd, &ui, si);
 		if (err < 0)
 			goto out_free;
 
-		err = format(mtd, &ui, si, err, 1, args.subpage_size);
+		err = format(args, mtd, &ui, si, err, 1);
 		if (err)
 			goto out_free;
 	} else {
-		err = format(mtd, &ui, si, 0, args.novtbl, args.subpage_size);
+		err = format(args, mtd, &ui, si, 0, args->novtbl);
 		if (err)
 			goto out_free;
 	}
-- 
2.8.0.rc3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/5] commands: ubiformat: create separate function for ubiformat
  2016-04-25 11:30 Create and use C API for ubiformat Sascha Hauer
  2016-04-25 11:30 ` [PATCH 1/5] commands: ubiformat: Pass around context data Sascha Hauer
@ 2016-04-25 11:30 ` Sascha Hauer
  2016-04-25 11:30 ` [PATCH 3/5] commands: ubiformat: move code to common/ Sascha Hauer
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2016-04-25 11:30 UTC (permalink / raw)
  To: Barebox List

Factor out the code out of the main function to a ubiformat function
to separate the command code from the ubiformat functionality.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 commands/ubiformat.c | 83 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 54 insertions(+), 29 deletions(-)

diff --git a/commands/ubiformat.c b/commands/ubiformat.c
index ec5e9d7..65c5ce9 100644
--- a/commands/ubiformat.c
+++ b/commands/ubiformat.c
@@ -71,7 +71,8 @@ struct ubiformat_args {
 	const char *node;
 };
 
-static int parse_opt(int argc, char *argv[], struct ubiformat_args *args)
+static int parse_opt(int argc, char *argv[], struct ubiformat_args *args,
+		     char **node)
 {
 	srand(get_time_ns());
 	memset(args, 0, sizeof(*args));
@@ -160,7 +161,8 @@ static int parse_opt(int argc, char *argv[], struct ubiformat_args *args)
 		return errmsg("-n cannot be used together with -f");
 
 
-	args->node = argv[optind];
+	*node = argv[optind];
+
 	return 0;
 }
 
@@ -555,35 +557,17 @@ out_free:
 	return -1;
 }
 
-int do_ubiformat(int argc, char *argv[])
+int ubiformat(struct mtd_info *mtd, struct ubiformat_args *args)
 {
-	int err, verbose, fd, eb_cnt;
-	struct mtd_info *mtd;
+	int err, verbose, eb_cnt;
 	struct ubigen_info ui;
 	struct ubi_scan_info *si;
-	struct mtd_info_user mtd_user;
 	int ubi_num;
-	struct ubiformat_args __args;
-	struct ubiformat_args *args = &__args;
-
-	err = parse_opt(argc, argv, args);
-	if (err)
-		return err;
-
-	fd = open(args->node, O_RDWR);
-	if (fd < 0)
-		return sys_errmsg("cannot open \"%s\"", args->node);
-
-	if (ioctl(fd, MEMGETINFO, &mtd_user)) {
-		sys_errmsg("MEMGETINFO ioctl request failed");
-		goto out_close;
-	}
-
-	mtd = mtd_user.mtd;
 
 	if (!is_power_of_2(mtd->writesize)) {
 		errmsg("min. I/O size is %d, but should be power of 2",
 		       mtd->writesize);
+		err = -EINVAL;
 		goto out_close;
 	}
 
@@ -598,12 +582,14 @@ int do_ubiformat(int argc, char *argv[])
 		/* Do some sanity check */
 		if (args->subpage_size > mtd->writesize) {
 			errmsg("sub-page cannot be larger than min. I/O unit");
+			err = -EINVAL;
 			goto out_close;
 		}
 
 		if (mtd->writesize % args->subpage_size) {
 			errmsg("min. I/O unit size should be multiple of "
 			       "sub-page size");
+			err = -EINVAL;
 			goto out_close;
 		}
 	}
@@ -612,20 +598,23 @@ int do_ubiformat(int argc, char *argv[])
 	if (args->vid_hdr_offs != 0) {
 		if (args->vid_hdr_offs % 8) {
 			errmsg("VID header offset has to be multiple of min. I/O unit size");
+			err = -EINVAL;
 			goto out_close;
 		}
 		if (args->vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd->erasesize) {
 			errmsg("bad VID header offset");
+			err = -EINVAL;
 			goto out_close;
 		}
 	}
 
 	if (!(mtd->flags & MTD_WRITEABLE)) {
 		errmsg("%s is a read-only device", args->node);
+		err = -EROFS;
 		goto out_close;
 	}
 
-	ubi_num = ubi_num_get_by_mtd(mtd_user.mtd);
+	ubi_num = ubi_num_get_by_mtd(mtd);
 	if (ubi_num >= 0) {
 		err = ubi_detach(ubi_num);
 		if (err) {
@@ -659,12 +648,14 @@ int do_ubiformat(int argc, char *argv[])
 
 	if (si->good_cnt == 0) {
 		errmsg("all %d eraseblocks are bad", si->bad_cnt);
+		err = -EINVAL;
 		goto out_free;
 	}
 
 	if (si->good_cnt < 2 && (!args->novtbl || args->image)) {
 		errmsg("too few non-bad eraseblocks (%d) on %s",
 		       si->good_cnt, args->node);
+		err = -EINVAL;
 		goto out_free;
 	}
 
@@ -685,8 +676,10 @@ int do_ubiformat(int argc, char *argv[])
 				si->alien_cnt, si->good_cnt);
 		if (!args->yes && !args->quiet)
 			warnmsg("use '-y' to force erasing");
-		if (!args->yes)
+		if (!args->yes) {
+			err = -EINVAL;
 			goto out_free;
+		}
 	}
 
 	if (!args->override_ec && si->empty_cnt < si->good_cnt) {
@@ -709,8 +702,10 @@ int do_ubiformat(int argc, char *argv[])
 				}
 			}
 
-			if (!args->yes)
+			if (!args->yes) {
+				err = -EINVAL;
 				goto out_free;
+			}
 
 			args->ec = 0;
 			args->override_ec = 1;
@@ -726,8 +721,10 @@ int do_ubiformat(int argc, char *argv[])
 					warnmsg("use '-y' to force erase counters");
 			}
 
-			if (!args->yes)
+			if (!args->yes) {
+				err = -EINVAL;
 				goto out_free;
+			}
 
 			args->ec = si->mean_ec;
 			args->override_ec = 1;
@@ -772,7 +769,7 @@ int do_ubiformat(int argc, char *argv[])
 
 	/* Reattach the ubi device in case it was attached in the beginning */
 	if (ubi_num >= 0) {
-		err = ubi_attach_mtd_dev(mtd_user.mtd, ubi_num, 0, 20);
+		err = ubi_attach_mtd_dev(mtd, ubi_num, 0, 20);
 		if (err) {
 			pr_err("Failed to reattach ubi device to ubi number %d, %d\n",
 			       ubi_num, err);
@@ -785,9 +782,37 @@ int do_ubiformat(int argc, char *argv[])
 out_free:
 	libscan_ubi_scan_free(si);
 out_close:
+
+	return err;
+}
+
+int do_ubiformat(int argc, char *argv[])
+{
+	int err, fd;
+	struct ubiformat_args args;
+	char *node = NULL;
+	struct mtd_info_user mtd_user;
+
+	err = parse_opt(argc, argv, &args, &node);
+	if (err)
+		return err;
+
+	fd = open(node, O_RDWR);
+	if (fd < 0)
+		return sys_errmsg("cannot open \"%s\"", node);
+
+	err = ioctl(fd, MEMGETINFO, &mtd_user);
+	if (err) {
+		sys_errmsg("MEMGETINFO ioctl request failed");
+		goto out_close;
+	}
+
+	err = ubiformat(mtd_user.mtd, &args);
+
+out_close:
 	close(fd);
 
-	return 1;
+	return err;
 }
 
 BAREBOX_CMD_HELP_START(ubiformat)
-- 
2.8.0.rc3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/5] commands: ubiformat: move code to common/
  2016-04-25 11:30 Create and use C API for ubiformat Sascha Hauer
  2016-04-25 11:30 ` [PATCH 1/5] commands: ubiformat: Pass around context data Sascha Hauer
  2016-04-25 11:30 ` [PATCH 2/5] commands: ubiformat: create separate function for ubiformat Sascha Hauer
@ 2016-04-25 11:30 ` Sascha Hauer
  2016-04-25 11:30 ` [PATCH 4/5] usb: fastboot: Use C API for ubiformat Sascha Hauer
  2016-04-25 11:30 ` [PATCH 5/5] usb: fastboot: drop CONFIG_COMMAND_SUPPORT dependency Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2016-04-25 11:30 UTC (permalink / raw)
  To: Barebox List

This is the final step to separate the ubiformat code from the
command. With this the ubiformat code gains a C API.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 commands/Kconfig     |   4 +-
 commands/ubiformat.c | 640 +-----------------------------------------------
 common/Kconfig       |   7 +
 common/Makefile      |   1 +
 common/ubiformat.c   | 675 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 686 insertions(+), 641 deletions(-)
 create mode 100644 common/ubiformat.c

diff --git a/commands/Kconfig b/commands/Kconfig
index 875c5f4..003adf0 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -693,9 +693,7 @@ config CMD_UBI
 
 config CMD_UBIFORMAT
 	tristate
-	depends on MTD_UBI
-	select LIBSCAN
-	select LIBUBIGEN
+	depends on UBIFORMAT
 	prompt "ubiformat"
 
 config CMD_UMOUNT
diff --git a/commands/ubiformat.c b/commands/ubiformat.c
index 65c5ce9..f4982c8 100644
--- a/commands/ubiformat.c
+++ b/commands/ubiformat.c
@@ -41,6 +41,7 @@
 #include <ioctl.h>
 #include <libbb.h>
 #include <libfile.h>
+#include <ubiformat.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/ubi.h>
 #include <linux/kernel.h>
@@ -54,23 +55,6 @@
 #include <mtd/ubi-media.h>
 #include <mtd/mtd-peb.h>
 
-/* The variables below are set by command line arguments */
-struct ubiformat_args {
-	unsigned int yes:1;
-	unsigned int quiet:1;
-	unsigned int verbose:1;
-	unsigned int override_ec:1;
-	unsigned int novtbl:1;
-	unsigned int manual_subpage;
-	int subpage_size;
-	int vid_hdr_offs;
-	int ubi_ver;
-	uint32_t image_seq;
-	long long ec;
-	const char *image;
-	const char *node;
-};
-
 static int parse_opt(int argc, char *argv[], struct ubiformat_args *args,
 		     char **node)
 {
@@ -166,627 +150,7 @@ static int parse_opt(int argc, char *argv[], struct ubiformat_args *args,
 	return 0;
 }
 
-static void print_bad_eraseblocks(struct mtd_info *mtd,
-				  const struct ubi_scan_info *si)
-{
-	int first = 1, eb, eb_cnt;
-
-	eb_cnt = mtd_div_by_eb(mtd->size, mtd);
-
-	if (si->bad_cnt == 0)
-		return;
-
-	normsg_cont("%d bad eraseblocks found, numbers: ", si->bad_cnt);
-	for (eb = 0; eb < eb_cnt; eb++) {
-		if (si->ec[eb] != EB_BAD)
-			continue;
-		if (first) {
-			printf("%d", eb);
-			first = 0;
-		} else
-			printf(", %d", eb);
-	}
-	printf("\n");
-}
-
-static int change_ech(struct ubi_ec_hdr *hdr, uint32_t image_seq,
-		      long long ec)
-{
-	uint32_t crc;
-
-	/* Check the EC header */
-	if (be32_to_cpu(hdr->magic) != UBI_EC_HDR_MAGIC)
-		return errmsg("bad UBI magic %#08x, should be %#08x",
-			      be32_to_cpu(hdr->magic), UBI_EC_HDR_MAGIC);
-
-	crc = crc32_no_comp(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
-	if (be32_to_cpu(hdr->hdr_crc) != crc)
-		return errmsg("bad CRC %#08x, should be %#08x\n",
-			      crc, be32_to_cpu(hdr->hdr_crc));
-
-	hdr->image_seq = cpu_to_be32(image_seq);
-	hdr->ec = cpu_to_be64(ec);
-	crc = crc32_no_comp(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
-	hdr->hdr_crc = cpu_to_be32(crc);
-
-	return 0;
-}
-
-static int drop_ffs(struct mtd_info *mtd, const void *buf, int len)
-{
-	int i;
-
-        for (i = len - 1; i >= 0; i--)
-		if (((const uint8_t *)buf)[i] != 0xFF)
-		      break;
-
-        /* The resulting length must be aligned to the minimum flash I/O size */
-	len = i + 1;
-	len = (len + mtd->writesize - 1) / mtd->writesize;
-	len *=  mtd->writesize;
-	return len;
-}
-
-static int open_file(const char *file, off_t *sz)
-{
-	int fd;
-	struct stat st;
-
-	if (stat(file, &st))
-		return sys_errmsg("cannot open \"%s\"", file);
-
-	*sz = st.st_size;
-	fd  = open(file, O_RDONLY);
-	if (fd < 0)
-		return sys_errmsg("cannot open \"%s\"", file);
-
-	return fd;
-}
-
-/*
- * Returns %-1 if consecutive bad blocks exceeds the
- * MAX_CONSECUTIVE_BAD_BLOCKS and returns %0 otherwise.
- */
-static int consecutive_bad_check(struct ubiformat_args *args, int eb)
-{
-	static int consecutive_bad_blocks = 1;
-	static int prev_bb = -1;
-
-	if (prev_bb == -1)
-		prev_bb = eb;
-
-	if (eb == prev_bb + 1)
-		consecutive_bad_blocks += 1;
-	else
-		consecutive_bad_blocks = 1;
-
-	prev_bb = eb;
-
-	if (consecutive_bad_blocks >= MAX_CONSECUTIVE_BAD_BLOCKS) {
-		if (!args->quiet)
-			printf("\n");
-		return errmsg("consecutive bad blocks exceed limit: %d, bad flash?",
-		              MAX_CONSECUTIVE_BAD_BLOCKS);
-	}
-
-	return 0;
-}
-
-/* TODO: we should actually torture the PEB before marking it as bad */
-static int mark_bad(struct ubiformat_args *args, struct mtd_info *mtd,
-		    struct ubi_scan_info *si, int eb)
-{
-	int err;
-
-	if (!args->quiet)
-		normsg_cont("marking block %d bad\n", eb);
-
-	if (!mtd_can_have_bb(mtd)) {
-		if (!args->quiet)
-			printf("\n");
-		return errmsg("bad blocks not supported by this flash");
-	}
-
-	err = mtd_peb_mark_bad(mtd, eb);
-	if (err)
-		return err;
-
-	si->bad_cnt += 1;
-	si->ec[eb] = EB_BAD;
-
-	return consecutive_bad_check(args, eb);
-}
-
-static int flash_image(struct ubiformat_args *args, struct mtd_info *mtd,
-		       const struct ubigen_info *ui, struct ubi_scan_info *si)
-{
-	int fd, img_ebs, eb, written_ebs = 0, ret = -1, eb_cnt;
-	off_t st_size;
-	char *buf = NULL;
-
-	eb_cnt = mtd_num_pebs(mtd);
-
-	fd = open_file(args->image, &st_size);
-	if (fd < 0)
-		return fd;
-
-	buf = malloc(mtd->erasesize);
-	if (!buf) {
-		sys_errmsg("cannot allocate %d bytes of memory", mtd->erasesize);
-		goto out_close;
-	}
-
-	img_ebs = st_size / mtd->erasesize;
-
-	if (img_ebs > si->good_cnt) {
-		sys_errmsg("file \"%s\" is too large (%lld bytes)",
-			   args->image, (long long)st_size);
-		goto out_close;
-	}
-
-	if (st_size % mtd->erasesize) {
-		sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of "
-			   "eraseblock size (%d bytes)",
-			   args->image, (long long)st_size, mtd->erasesize);
-		goto out_close;
-	}
-
-	if (st_size == 0) {
-		sys_errmsg("file \"%s\" has size 0 bytes", args->image);
-		goto out_close;
-	}
-
-	verbose(args->verbose, "will write %d eraseblocks", img_ebs);
-	for (eb = 0; eb < eb_cnt; eb++) {
-		int err, new_len;
-		long long ec;
-
-		if (!args->quiet && !args->verbose) {
-			printf("\rubiformat: flashing eraseblock %d -- %2u %% complete  ",
-			       eb, (eb + 1) * 100 / eb_cnt);
-		}
-
-		if (si->ec[eb] == EB_BAD)
-			continue;
-
-		if (args->verbose) {
-			normsg_cont("eraseblock %d: erase", eb);
-		}
-
-		err = mtd_peb_erase(mtd, eb);
-		if (err) {
-			if (!args->quiet)
-				printf("\n");
-			sys_errmsg("failed to erase eraseblock %d", eb);
-
-			if (err != EIO)
-				goto out_close;
-
-			if (mark_bad(args, mtd, si, eb))
-				goto out_close;
-
-			continue;
-		}
-
-		err = read_full(fd, buf, mtd->erasesize);
-		if (err < 0) {
-			sys_errmsg("failed to read eraseblock %d from \"%s\"",
-				   written_ebs, args->image);
-			goto out_close;
-		}
-
-		if (args->override_ec)
-			ec = args->ec;
-		else if (si->ec[eb] <= EC_MAX)
-			ec = si->ec[eb] + 1;
-		else
-			ec = si->mean_ec;
-
-		if (args->verbose) {
-			printf(", change EC to %lld", ec);
-		}
-
-		err = change_ech((struct ubi_ec_hdr *)buf, ui->image_seq, ec);
-		if (err) {
-			errmsg("bad EC header at eraseblock %d of \"%s\"",
-			       written_ebs, args->image);
-			goto out_close;
-		}
-
-		if (args->verbose) {
-			printf(", write data\n");
-		}
-
-		new_len = drop_ffs(mtd, buf, mtd->erasesize);
-
-		err = mtd_peb_write(mtd, buf, eb, 0, new_len);
-		if (err) {
-			sys_errmsg("cannot write eraseblock %d", eb);
-
-			if (err != EIO)
-				goto out_close;
-
-			err = mtd_peb_torture(mtd, eb);
-			if (err < 0 && err != -EIO)
-				goto out_close;
-			if (err == -EIO && consecutive_bad_check(args, eb))
-				goto out_close;
-
-			continue;
-		}
-		if (++written_ebs >= img_ebs)
-			break;
-	}
-
-	if (!args->quiet && !args->verbose)
-		printf("\n");
-
-	ret = eb + 1;
-
-out_close:
-	free(buf);
-	close(fd);
-	return ret;
-}
-
-static int format(struct ubiformat_args *args, struct mtd_info *mtd,
-		  const struct ubigen_info *ui, struct ubi_scan_info *si,
-		  int start_eb, int novtbl)
-{
-	int eb, err, write_size, eb_cnt;
-	struct ubi_ec_hdr *hdr;
-	struct ubi_vtbl_record *vtbl;
-	int eb1 = -1, eb2 = -1;
-	long long ec1 = -1, ec2 = -1;
-
-	eb_cnt = mtd_num_pebs(mtd);
-
-	write_size = UBI_EC_HDR_SIZE + args->subpage_size - 1;
-	write_size /= args->subpage_size;
-	write_size *= args->subpage_size;
-	hdr = malloc(write_size);
-	if (!hdr)
-		return sys_errmsg("cannot allocate %d bytes of memory", write_size);
-	memset(hdr, 0xFF, write_size);
-
-	for (eb = start_eb; eb < eb_cnt; eb++) {
-		long long ec;
-
-		if (!args->quiet && !args->verbose) {
-			printf("\rubiformat: formatting eraseblock %d -- %2u %% complete  ",
-			       eb, (eb + 1 - start_eb) * 100 / (eb_cnt - start_eb));
-		}
-
-		if (si->ec[eb] == EB_BAD)
-			continue;
-
-		if (args->override_ec)
-			ec = args->ec;
-		else if (si->ec[eb] <= EC_MAX)
-			ec = si->ec[eb] + 1;
-		else
-			ec = si->mean_ec;
-		ubigen_init_ec_hdr(ui, hdr, ec);
-
-		if (args->verbose) {
-			normsg_cont("eraseblock %d: erase", eb);
-		}
-
-		err = mtd_peb_erase(mtd, eb);
-		if (err) {
-			if (!args->quiet)
-				printf("\n");
-
-			sys_errmsg("failed to erase eraseblock %d", eb);
-			if (err != EIO)
-				goto out_free;
-
-			if (mark_bad(args, mtd, si, eb))
-				goto out_free;
-			continue;
-		}
-
-		if ((eb1 == -1 || eb2 == -1) && !novtbl) {
-			if (eb1 == -1) {
-				eb1 = eb;
-				ec1 = ec;
-			} else if (eb2 == -1) {
-				eb2 = eb;
-				ec2 = ec;
-			}
-			if (args->verbose)
-				printf(", do not write EC, leave for vtbl\n");
-			continue;
-		}
-
-		if (args->verbose) {
-			printf(", write EC %lld\n", ec);
-		}
-
-		err = mtd_peb_write(mtd, hdr, eb, 0, write_size);
-		if (err) {
-			if (!args->quiet && !args->verbose)
-				printf("\n");
-			sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d",
-				   write_size, eb);
-
-			if (errno != EIO) {
-				if (args->subpage_size != mtd->writesize)
-					normsg("may be sub-page size is incorrect?");
-				goto out_free;
-			}
-
-			err = mtd_peb_torture(mtd, eb);
-			if (err < 0 && err != -EIO)
-				goto out_free;
-			if (err == -EIO && consecutive_bad_check(args, eb))
-				goto out_free;
-
-			continue;
-
-		}
-	}
-
-	if (!args->quiet && !args->verbose)
-		printf("\n");
-
-	if (!novtbl) {
-		if (eb1 == -1 || eb2 == -1) {
-			errmsg("no eraseblocks for volume table");
-			goto out_free;
-		}
-
-		verbose(args->verbose, "write volume table to eraseblocks %d and %d", eb1, eb2);
-		vtbl = ubigen_create_empty_vtbl(ui);
-		if (!vtbl)
-			goto out_free;
-
-		err = ubigen_write_layout_vol(ui, eb1, eb2, ec1,  ec2, vtbl, mtd);
-		free(vtbl);
-		if (err) {
-			errmsg("cannot write layout volume");
-			goto out_free;
-		}
-	}
-
-	free(hdr);
-	return 0;
-
-out_free:
-	free(hdr);
-	return -1;
-}
-
-int ubiformat(struct mtd_info *mtd, struct ubiformat_args *args)
-{
-	int err, verbose, eb_cnt;
-	struct ubigen_info ui;
-	struct ubi_scan_info *si;
-	int ubi_num;
-
-	if (!is_power_of_2(mtd->writesize)) {
-		errmsg("min. I/O size is %d, but should be power of 2",
-		       mtd->writesize);
-		err = -EINVAL;
-		goto out_close;
-	}
-
-	if (args->subpage_size) {
-		if (args->subpage_size != mtd->writesize >> mtd->subpage_sft)
-			args->manual_subpage = 1;
-	} else {
-		args->subpage_size = mtd->writesize >> mtd->subpage_sft;
-	}
-
-	if (args->manual_subpage) {
-		/* Do some sanity check */
-		if (args->subpage_size > mtd->writesize) {
-			errmsg("sub-page cannot be larger than min. I/O unit");
-			err = -EINVAL;
-			goto out_close;
-		}
-
-		if (mtd->writesize % args->subpage_size) {
-			errmsg("min. I/O unit size should be multiple of "
-			       "sub-page size");
-			err = -EINVAL;
-			goto out_close;
-		}
-	}
-
-	/* Validate VID header offset if it was specified */
-	if (args->vid_hdr_offs != 0) {
-		if (args->vid_hdr_offs % 8) {
-			errmsg("VID header offset has to be multiple of min. I/O unit size");
-			err = -EINVAL;
-			goto out_close;
-		}
-		if (args->vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd->erasesize) {
-			errmsg("bad VID header offset");
-			err = -EINVAL;
-			goto out_close;
-		}
-	}
-
-	if (!(mtd->flags & MTD_WRITEABLE)) {
-		errmsg("%s is a read-only device", args->node);
-		err = -EROFS;
-		goto out_close;
-	}
-
-	ubi_num = ubi_num_get_by_mtd(mtd);
-	if (ubi_num >= 0) {
-		err = ubi_detach(ubi_num);
-		if (err) {
-			sys_errmsg("Cannot detach %d\n", err);
-			goto out_close;
-		}
-	}
-
-
-	eb_cnt = mtd_div_by_eb(mtd->size, mtd);
-
-	if (!args->quiet) {
-		normsg_cont("%s (%s), size %lld bytes (%s)", args->node, mtd_type_str(mtd),
-			mtd->size, size_human_readable(mtd->size));
-		printf(", %d eraseblocks of %d bytes (%s)", eb_cnt,
-			mtd->erasesize, size_human_readable(mtd->erasesize));
-		printf(", min. I/O size %d bytes\n", mtd->writesize);
-	}
-
-	if (args->quiet)
-		verbose = 0;
-	else if (args->verbose)
-		verbose = 2;
-	else
-		verbose = 1;
-	err = libscan_ubi_scan(mtd, &si, verbose);
-	if (err) {
-		errmsg("failed to scan %s", args->node);
-		goto out_close;
-	}
-
-	if (si->good_cnt == 0) {
-		errmsg("all %d eraseblocks are bad", si->bad_cnt);
-		err = -EINVAL;
-		goto out_free;
-	}
-
-	if (si->good_cnt < 2 && (!args->novtbl || args->image)) {
-		errmsg("too few non-bad eraseblocks (%d) on %s",
-		       si->good_cnt, args->node);
-		err = -EINVAL;
-		goto out_free;
-	}
-
-	if (!args->quiet) {
-		if (si->ok_cnt)
-			normsg("%d eraseblocks have valid erase counter, mean value is %lld",
-			       si->ok_cnt, si->mean_ec);
-		if (si->empty_cnt)
-			normsg("%d eraseblocks are supposedly empty", si->empty_cnt);
-		if (si->corrupted_cnt)
-			normsg("%d corrupted erase counters", si->corrupted_cnt);
-		print_bad_eraseblocks(mtd, si);
-	}
-
-	if (si->alien_cnt) {
-		if (!args->quiet)
-			warnmsg("%d of %d eraseblocks contain non-ubifs data",
-				si->alien_cnt, si->good_cnt);
-		if (!args->yes && !args->quiet)
-			warnmsg("use '-y' to force erasing");
-		if (!args->yes) {
-			err = -EINVAL;
-			goto out_free;
-		}
-	}
-
-	if (!args->override_ec && si->empty_cnt < si->good_cnt) {
-		int percent = (si->ok_cnt * 100) / si->good_cnt;
-
-		/*
-		 * Make sure the majority of eraseblocks have valid
-		 * erase counters.
-		 */
-		if (percent < 50) {
-			if (!args->quiet) {
-				warnmsg("only %d of %d eraseblocks have valid erase counter",
-					si->ok_cnt, si->good_cnt);
-				if (args->yes) {
-					normsg("erase counter 0 will be used for all eraseblocks");
-					normsg("note, arbitrary erase counter value may be specified using -e option");
-
-				} else {
-					warnmsg("use '-y' to force erase counters");
-				}
-			}
-
-			if (!args->yes) {
-				err = -EINVAL;
-				goto out_free;
-			}
-
-			args->ec = 0;
-			args->override_ec = 1;
-
-		} else if (percent < 95) {
-			if (!args->quiet) {
-				warnmsg("only %d of %d eraseblocks have valid erase counter",
-					si->ok_cnt, si->good_cnt);
-				if (args->yes)
-					normsg("mean erase counter %lld will be used for the rest of eraseblock",
-					       si->mean_ec);
-				else
-					warnmsg("use '-y' to force erase counters");
-			}
-
-			if (!args->yes) {
-				err = -EINVAL;
-				goto out_free;
-			}
-
-			args->ec = si->mean_ec;
-			args->override_ec = 1;
-		}
-	}
-
-	if (!args->quiet && args->override_ec)
-		normsg("use erase counter %lld for all eraseblocks", args->ec);
-
-	ubigen_info_init(&ui, mtd->erasesize, mtd->writesize, args->subpage_size,
-			 args->vid_hdr_offs, args->ubi_ver, args->image_seq);
-
-	if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
-		/*
-		 * Hmm, what we read from flash and what we calculated using
-		 * min. I/O unit size and sub-page size differs.
-		 */
-		if (!args->quiet) {
-			warnmsg("VID header and data offsets on flash are %d and %d, "
-				"which is different to requested offsets %d and %d",
-				si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs,
-				ui.data_offs);
-			normsg("using offsets %d and %d",  ui.vid_hdr_offs, ui.data_offs);
-		}
-	}
-
-	if (args->image) {
-		err = flash_image(args, mtd, &ui, si);
-		if (err < 0)
-			goto out_free;
-
-		err = format(args, mtd, &ui, si, err, 1);
-		if (err)
-			goto out_free;
-	} else {
-		err = format(args, mtd, &ui, si, 0, args->novtbl);
-		if (err)
-			goto out_free;
-	}
-
-	libscan_ubi_scan_free(si);
-
-	/* Reattach the ubi device in case it was attached in the beginning */
-	if (ubi_num >= 0) {
-		err = ubi_attach_mtd_dev(mtd, ubi_num, 0, 20);
-		if (err) {
-			pr_err("Failed to reattach ubi device to ubi number %d, %d\n",
-			       ubi_num, err);
-			return err;
-		}
-	}
-
-	return 0;
-
-out_free:
-	libscan_ubi_scan_free(si);
-out_close:
-
-	return err;
-}
-
-int do_ubiformat(int argc, char *argv[])
+static int do_ubiformat(int argc, char *argv[])
 {
 	int err, fd;
 	struct ubiformat_args args;
diff --git a/common/Kconfig b/common/Kconfig
index 7c09e8c..7fa7d8a 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -114,6 +114,13 @@ config BAREBOX_UPDATE_IMX_NAND_FCB
 	depends on NAND_MXS
 	default y
 
+config UBIFORMAT
+	bool
+	select LIBSCAN
+	select LIBUBIGEN
+	depends on MTD_UBI
+	default y
+
 menu "General Settings"
 
 config LOCALVERSION
diff --git a/common/Makefile b/common/Makefile
index d99ca7b..99681e2 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -55,6 +55,7 @@ lwl-$(CONFIG_IMD)		+= imd-barebox.o
 obj-$(CONFIG_IMD)		+= imd.o
 obj-$(CONFIG_FILE_LIST)		+= file-list.o
 obj-$(CONFIG_FIRMWARE)		+= firmware.o
+obj-$(CONFIG_UBIFORMAT)		+= ubiformat.o
 obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o
 obj-$(CONFIG_CONSOLE_RATP)	+= ratp.o
 
diff --git a/common/ubiformat.c b/common/ubiformat.c
new file mode 100644
index 0000000..e4f569b
--- /dev/null
+++ b/common/ubiformat.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ */
+
+/*
+ * An utility to format MTD devices into UBI and flash UBI images.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+/*
+ * Maximum amount of consequtive eraseblocks which are considered as normal by
+ * this utility. Otherwise it is assume that something is wrong with the flash
+ * or the driver, and eraseblocks are stopped being marked as bad.
+ */
+#define MAX_CONSECUTIVE_BAD_BLOCKS 4
+
+#define PROGRAM_NAME	"ubiformat"
+
+#include <common.h>
+#include <fs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <crc.h>
+#include <stdlib.h>
+#include <clock.h>
+#include <malloc.h>
+#include <ioctl.h>
+#include <libbb.h>
+#include <libfile.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/ubi.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/log2.h>
+#include <linux/mtd/mtd-abi.h>
+#include <mtd/libscan.h>
+#include <mtd/libubigen.h>
+#include <mtd/ubi-user.h>
+#include <mtd/utils.h>
+#include <mtd/ubi-media.h>
+#include <mtd/mtd-peb.h>
+#include <ubiformat.h>
+
+static void print_bad_eraseblocks(struct mtd_info *mtd,
+				  const struct ubi_scan_info *si)
+{
+	int first = 1, eb, eb_cnt;
+
+	eb_cnt = mtd_div_by_eb(mtd->size, mtd);
+
+	if (si->bad_cnt == 0)
+		return;
+
+	normsg_cont("%d bad eraseblocks found, numbers: ", si->bad_cnt);
+	for (eb = 0; eb < eb_cnt; eb++) {
+		if (si->ec[eb] != EB_BAD)
+			continue;
+		if (first) {
+			printf("%d", eb);
+			first = 0;
+		} else
+			printf(", %d", eb);
+	}
+	printf("\n");
+}
+
+static int change_ech(struct ubi_ec_hdr *hdr, uint32_t image_seq,
+		      long long ec)
+{
+	uint32_t crc;
+
+	/* Check the EC header */
+	if (be32_to_cpu(hdr->magic) != UBI_EC_HDR_MAGIC)
+		return errmsg("bad UBI magic %#08x, should be %#08x",
+			      be32_to_cpu(hdr->magic), UBI_EC_HDR_MAGIC);
+
+	crc = crc32_no_comp(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+	if (be32_to_cpu(hdr->hdr_crc) != crc)
+		return errmsg("bad CRC %#08x, should be %#08x\n",
+			      crc, be32_to_cpu(hdr->hdr_crc));
+
+	hdr->image_seq = cpu_to_be32(image_seq);
+	hdr->ec = cpu_to_be64(ec);
+	crc = crc32_no_comp(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+	hdr->hdr_crc = cpu_to_be32(crc);
+
+	return 0;
+}
+
+static int drop_ffs(struct mtd_info *mtd, const void *buf, int len)
+{
+	int i;
+
+        for (i = len - 1; i >= 0; i--)
+		if (((const uint8_t *)buf)[i] != 0xFF)
+		      break;
+
+        /* The resulting length must be aligned to the minimum flash I/O size */
+	len = i + 1;
+	len = (len + mtd->writesize - 1) / mtd->writesize;
+	len *=  mtd->writesize;
+	return len;
+}
+
+static int open_file(const char *file, off_t *sz)
+{
+	int fd;
+	struct stat st;
+
+	if (stat(file, &st))
+		return sys_errmsg("cannot open \"%s\"", file);
+
+	*sz = st.st_size;
+	fd  = open(file, O_RDONLY);
+	if (fd < 0)
+		return sys_errmsg("cannot open \"%s\"", file);
+
+	return fd;
+}
+
+/*
+ * Returns %-1 if consecutive bad blocks exceeds the
+ * MAX_CONSECUTIVE_BAD_BLOCKS and returns %0 otherwise.
+ */
+static int consecutive_bad_check(struct ubiformat_args *args, int eb)
+{
+	static int consecutive_bad_blocks = 1;
+	static int prev_bb = -1;
+
+	if (prev_bb == -1)
+		prev_bb = eb;
+
+	if (eb == prev_bb + 1)
+		consecutive_bad_blocks += 1;
+	else
+		consecutive_bad_blocks = 1;
+
+	prev_bb = eb;
+
+	if (consecutive_bad_blocks >= MAX_CONSECUTIVE_BAD_BLOCKS) {
+		if (!args->quiet)
+			printf("\n");
+		return errmsg("consecutive bad blocks exceed limit: %d, bad flash?",
+		              MAX_CONSECUTIVE_BAD_BLOCKS);
+	}
+
+	return 0;
+}
+
+/* TODO: we should actually torture the PEB before marking it as bad */
+static int mark_bad(struct ubiformat_args *args, struct mtd_info *mtd,
+		    struct ubi_scan_info *si, int eb)
+{
+	int err;
+
+	if (!args->quiet)
+		normsg_cont("marking block %d bad\n", eb);
+
+	if (!mtd_can_have_bb(mtd)) {
+		if (!args->quiet)
+			printf("\n");
+		return errmsg("bad blocks not supported by this flash");
+	}
+
+	err = mtd_peb_mark_bad(mtd, eb);
+	if (err)
+		return err;
+
+	si->bad_cnt += 1;
+	si->ec[eb] = EB_BAD;
+
+	return consecutive_bad_check(args, eb);
+}
+
+static int flash_image(struct ubiformat_args *args, struct mtd_info *mtd,
+		       const struct ubigen_info *ui, struct ubi_scan_info *si)
+{
+	int fd, img_ebs, eb, written_ebs = 0, ret = -1, eb_cnt;
+	off_t st_size;
+	char *buf = NULL;
+
+	eb_cnt = mtd_num_pebs(mtd);
+
+	fd = open_file(args->image, &st_size);
+	if (fd < 0)
+		return fd;
+
+	buf = malloc(mtd->erasesize);
+	if (!buf) {
+		sys_errmsg("cannot allocate %d bytes of memory", mtd->erasesize);
+		goto out_close;
+	}
+
+	img_ebs = st_size / mtd->erasesize;
+
+	if (img_ebs > si->good_cnt) {
+		sys_errmsg("file \"%s\" is too large (%lld bytes)",
+			   args->image, (long long)st_size);
+		goto out_close;
+	}
+
+	if (st_size % mtd->erasesize) {
+		sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of "
+			   "eraseblock size (%d bytes)",
+			   args->image, (long long)st_size, mtd->erasesize);
+		goto out_close;
+	}
+
+	if (st_size == 0) {
+		sys_errmsg("file \"%s\" has size 0 bytes", args->image);
+		goto out_close;
+	}
+
+	verbose(args->verbose, "will write %d eraseblocks", img_ebs);
+	for (eb = 0; eb < eb_cnt; eb++) {
+		int err, new_len;
+		long long ec;
+
+		if (!args->quiet && !args->verbose) {
+			printf("\rubiformat: flashing eraseblock %d -- %2u %% complete  ",
+			       eb, (eb + 1) * 100 / eb_cnt);
+		}
+
+		if (si->ec[eb] == EB_BAD)
+			continue;
+
+		if (args->verbose) {
+			normsg_cont("eraseblock %d: erase", eb);
+		}
+
+		err = mtd_peb_erase(mtd, eb);
+		if (err) {
+			if (!args->quiet)
+				printf("\n");
+			sys_errmsg("failed to erase eraseblock %d", eb);
+
+			if (err != EIO)
+				goto out_close;
+
+			if (mark_bad(args, mtd, si, eb))
+				goto out_close;
+
+			continue;
+		}
+
+		err = read_full(fd, buf, mtd->erasesize);
+		if (err < 0) {
+			sys_errmsg("failed to read eraseblock %d from \"%s\"",
+				   written_ebs, args->image);
+			goto out_close;
+		}
+
+		if (args->override_ec)
+			ec = args->ec;
+		else if (si->ec[eb] <= EC_MAX)
+			ec = si->ec[eb] + 1;
+		else
+			ec = si->mean_ec;
+
+		if (args->verbose) {
+			printf(", change EC to %lld", ec);
+		}
+
+		err = change_ech((struct ubi_ec_hdr *)buf, ui->image_seq, ec);
+		if (err) {
+			errmsg("bad EC header at eraseblock %d of \"%s\"",
+			       written_ebs, args->image);
+			goto out_close;
+		}
+
+		if (args->verbose) {
+			printf(", write data\n");
+		}
+
+		new_len = drop_ffs(mtd, buf, mtd->erasesize);
+
+		err = mtd_peb_write(mtd, buf, eb, 0, new_len);
+		if (err) {
+			sys_errmsg("cannot write eraseblock %d", eb);
+
+			if (err != EIO)
+				goto out_close;
+
+			err = mtd_peb_torture(mtd, eb);
+			if (err < 0 && err != -EIO)
+				goto out_close;
+			if (err == -EIO && consecutive_bad_check(args, eb))
+				goto out_close;
+
+			continue;
+		}
+		if (++written_ebs >= img_ebs)
+			break;
+	}
+
+	if (!args->quiet && !args->verbose)
+		printf("\n");
+
+	ret = eb + 1;
+
+out_close:
+	free(buf);
+	close(fd);
+	return ret;
+}
+
+static int format(struct ubiformat_args *args, struct mtd_info *mtd,
+		  const struct ubigen_info *ui, struct ubi_scan_info *si,
+		  int start_eb, int novtbl)
+{
+	int eb, err, write_size, eb_cnt;
+	struct ubi_ec_hdr *hdr;
+	struct ubi_vtbl_record *vtbl;
+	int eb1 = -1, eb2 = -1;
+	long long ec1 = -1, ec2 = -1;
+
+	eb_cnt = mtd_num_pebs(mtd);
+
+	write_size = UBI_EC_HDR_SIZE + args->subpage_size - 1;
+	write_size /= args->subpage_size;
+	write_size *= args->subpage_size;
+	hdr = malloc(write_size);
+	if (!hdr)
+		return sys_errmsg("cannot allocate %d bytes of memory", write_size);
+	memset(hdr, 0xFF, write_size);
+
+	for (eb = start_eb; eb < eb_cnt; eb++) {
+		long long ec;
+
+		if (!args->quiet && !args->verbose) {
+			printf("\rubiformat: formatting eraseblock %d -- %2u %% complete  ",
+			       eb, (eb + 1 - start_eb) * 100 / (eb_cnt - start_eb));
+		}
+
+		if (si->ec[eb] == EB_BAD)
+			continue;
+
+		if (args->override_ec)
+			ec = args->ec;
+		else if (si->ec[eb] <= EC_MAX)
+			ec = si->ec[eb] + 1;
+		else
+			ec = si->mean_ec;
+		ubigen_init_ec_hdr(ui, hdr, ec);
+
+		if (args->verbose) {
+			normsg_cont("eraseblock %d: erase", eb);
+		}
+
+		err = mtd_peb_erase(mtd, eb);
+		if (err) {
+			if (!args->quiet)
+				printf("\n");
+
+			sys_errmsg("failed to erase eraseblock %d", eb);
+			if (err != EIO)
+				goto out_free;
+
+			if (mark_bad(args, mtd, si, eb))
+				goto out_free;
+			continue;
+		}
+
+		if ((eb1 == -1 || eb2 == -1) && !novtbl) {
+			if (eb1 == -1) {
+				eb1 = eb;
+				ec1 = ec;
+			} else if (eb2 == -1) {
+				eb2 = eb;
+				ec2 = ec;
+			}
+			if (args->verbose)
+				printf(", do not write EC, leave for vtbl\n");
+			continue;
+		}
+
+		if (args->verbose) {
+			printf(", write EC %lld\n", ec);
+		}
+
+		err = mtd_peb_write(mtd, hdr, eb, 0, write_size);
+		if (err) {
+			if (!args->quiet && !args->verbose)
+				printf("\n");
+			sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d",
+				   write_size, eb);
+
+			if (errno != EIO) {
+				if (args->subpage_size != mtd->writesize)
+					normsg("may be sub-page size is incorrect?");
+				goto out_free;
+			}
+
+			err = mtd_peb_torture(mtd, eb);
+			if (err < 0 && err != -EIO)
+				goto out_free;
+			if (err == -EIO && consecutive_bad_check(args, eb))
+				goto out_free;
+
+			continue;
+
+		}
+	}
+
+	if (!args->quiet && !args->verbose)
+		printf("\n");
+
+	if (!novtbl) {
+		if (eb1 == -1 || eb2 == -1) {
+			errmsg("no eraseblocks for volume table");
+			goto out_free;
+		}
+
+		verbose(args->verbose, "write volume table to eraseblocks %d and %d", eb1, eb2);
+		vtbl = ubigen_create_empty_vtbl(ui);
+		if (!vtbl)
+			goto out_free;
+
+		err = ubigen_write_layout_vol(ui, eb1, eb2, ec1,  ec2, vtbl, mtd);
+		free(vtbl);
+		if (err) {
+			errmsg("cannot write layout volume");
+			goto out_free;
+		}
+	}
+
+	free(hdr);
+	return 0;
+
+out_free:
+	free(hdr);
+	return -1;
+}
+
+int ubiformat(struct mtd_info *mtd, struct ubiformat_args *args)
+{
+	int err, verbose, eb_cnt;
+	struct ubigen_info ui;
+	struct ubi_scan_info *si;
+	int ubi_num;
+
+	if (!is_power_of_2(mtd->writesize)) {
+		errmsg("min. I/O size is %d, but should be power of 2",
+		       mtd->writesize);
+		err = -EINVAL;
+		goto out_close;
+	}
+
+	if (args->subpage_size) {
+		if (args->subpage_size != mtd->writesize >> mtd->subpage_sft)
+			args->manual_subpage = 1;
+	} else {
+		args->subpage_size = mtd->writesize >> mtd->subpage_sft;
+	}
+
+	if (args->manual_subpage) {
+		/* Do some sanity check */
+		if (args->subpage_size > mtd->writesize) {
+			errmsg("sub-page cannot be larger than min. I/O unit");
+			err = -EINVAL;
+			goto out_close;
+		}
+
+		if (mtd->writesize % args->subpage_size) {
+			errmsg("min. I/O unit size should be multiple of "
+			       "sub-page size");
+			err = -EINVAL;
+			goto out_close;
+		}
+	}
+
+	/* Validate VID header offset if it was specified */
+	if (args->vid_hdr_offs != 0) {
+		if (args->vid_hdr_offs % 8) {
+			errmsg("VID header offset has to be multiple of min. I/O unit size");
+			err = -EINVAL;
+			goto out_close;
+		}
+		if (args->vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd->erasesize) {
+			errmsg("bad VID header offset");
+			err = -EINVAL;
+			goto out_close;
+		}
+	}
+
+	if (!(mtd->flags & MTD_WRITEABLE)) {
+		errmsg("%s is a read-only device", mtd->name);
+		err = -EROFS;
+		goto out_close;
+	}
+
+	ubi_num = ubi_num_get_by_mtd(mtd);
+	if (ubi_num >= 0) {
+		err = ubi_detach(ubi_num);
+		if (err) {
+			sys_errmsg("Cannot detach %d\n", err);
+			goto out_close;
+		}
+	}
+
+
+	eb_cnt = mtd_div_by_eb(mtd->size, mtd);
+
+	if (!args->quiet) {
+		normsg_cont("%s (%s), size %lld bytes (%s)", mtd->name, mtd_type_str(mtd),
+			mtd->size, size_human_readable(mtd->size));
+		printf(", %d eraseblocks of %d bytes (%s)", eb_cnt,
+			mtd->erasesize, size_human_readable(mtd->erasesize));
+		printf(", min. I/O size %d bytes\n", mtd->writesize);
+	}
+
+	if (args->quiet)
+		verbose = 0;
+	else if (args->verbose)
+		verbose = 2;
+	else
+		verbose = 1;
+	err = libscan_ubi_scan(mtd, &si, verbose);
+	if (err) {
+		errmsg("failed to scan %s", mtd->name);
+		goto out_close;
+	}
+
+	if (si->good_cnt == 0) {
+		errmsg("all %d eraseblocks are bad", si->bad_cnt);
+		err = -EINVAL;
+		goto out_free;
+	}
+
+	if (si->good_cnt < 2 && (!args->novtbl || args->image)) {
+		errmsg("too few non-bad eraseblocks (%d) on %s",
+		       si->good_cnt, mtd->name);
+		err = -EINVAL;
+		goto out_free;
+	}
+
+	if (!args->quiet) {
+		if (si->ok_cnt)
+			normsg("%d eraseblocks have valid erase counter, mean value is %lld",
+			       si->ok_cnt, si->mean_ec);
+		if (si->empty_cnt)
+			normsg("%d eraseblocks are supposedly empty", si->empty_cnt);
+		if (si->corrupted_cnt)
+			normsg("%d corrupted erase counters", si->corrupted_cnt);
+		print_bad_eraseblocks(mtd, si);
+	}
+
+	if (si->alien_cnt) {
+		if (!args->quiet)
+			warnmsg("%d of %d eraseblocks contain non-ubifs data",
+				si->alien_cnt, si->good_cnt);
+		if (!args->yes && !args->quiet)
+			warnmsg("use '-y' to force erasing");
+		if (!args->yes) {
+			err = -EINVAL;
+			goto out_free;
+		}
+	}
+
+	if (!args->override_ec && si->empty_cnt < si->good_cnt) {
+		int percent = (si->ok_cnt * 100) / si->good_cnt;
+
+		/*
+		 * Make sure the majority of eraseblocks have valid
+		 * erase counters.
+		 */
+		if (percent < 50) {
+			if (!args->quiet) {
+				warnmsg("only %d of %d eraseblocks have valid erase counter",
+					si->ok_cnt, si->good_cnt);
+				if (args->yes) {
+					normsg("erase counter 0 will be used for all eraseblocks");
+					normsg("note, arbitrary erase counter value may be specified using -e option");
+
+				} else {
+					warnmsg("use '-y' to force erase counters");
+				}
+			}
+
+			if (!args->yes) {
+				err = -EINVAL;
+				goto out_free;
+			}
+
+			args->ec = 0;
+			args->override_ec = 1;
+
+		} else if (percent < 95) {
+			if (!args->quiet) {
+				warnmsg("only %d of %d eraseblocks have valid erase counter",
+					si->ok_cnt, si->good_cnt);
+				if (args->yes)
+					normsg("mean erase counter %lld will be used for the rest of eraseblock",
+					       si->mean_ec);
+				else
+					warnmsg("use '-y' to force erase counters");
+			}
+
+			if (!args->yes) {
+				err = -EINVAL;
+				goto out_free;
+			}
+
+			args->ec = si->mean_ec;
+			args->override_ec = 1;
+		}
+	}
+
+	if (!args->quiet && args->override_ec)
+		normsg("use erase counter %lld for all eraseblocks", args->ec);
+
+	ubigen_info_init(&ui, mtd->erasesize, mtd->writesize, args->subpage_size,
+			 args->vid_hdr_offs, args->ubi_ver, args->image_seq);
+
+	if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
+		/*
+		 * Hmm, what we read from flash and what we calculated using
+		 * min. I/O unit size and sub-page size differs.
+		 */
+		if (!args->quiet) {
+			warnmsg("VID header and data offsets on flash are %d and %d, "
+				"which is different to requested offsets %d and %d",
+				si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs,
+				ui.data_offs);
+			normsg("using offsets %d and %d",  ui.vid_hdr_offs, ui.data_offs);
+		}
+	}
+
+	if (args->image) {
+		err = flash_image(args, mtd, &ui, si);
+		if (err < 0)
+			goto out_free;
+
+		err = format(args, mtd, &ui, si, err, 1);
+		if (err)
+			goto out_free;
+	} else {
+		err = format(args, mtd, &ui, si, 0, args->novtbl);
+		if (err)
+			goto out_free;
+	}
+
+	libscan_ubi_scan_free(si);
+
+	/* Reattach the ubi device in case it was attached in the beginning */
+	if (ubi_num >= 0) {
+		err = ubi_attach_mtd_dev(mtd, ubi_num, 0, 20);
+		if (err) {
+			pr_err("Failed to reattach ubi device to ubi number %d, %d\n",
+			       ubi_num, err);
+			return err;
+		}
+	}
+
+	return 0;
+
+out_free:
+	libscan_ubi_scan_free(si);
+out_close:
+
+	return err;
+}
+
-- 
2.8.0.rc3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 4/5] usb: fastboot: Use C API for ubiformat
  2016-04-25 11:30 Create and use C API for ubiformat Sascha Hauer
                   ` (2 preceding siblings ...)
  2016-04-25 11:30 ` [PATCH 3/5] commands: ubiformat: move code to common/ Sascha Hauer
@ 2016-04-25 11:30 ` Sascha Hauer
  2016-04-25 11:30 ` [PATCH 5/5] usb: fastboot: drop CONFIG_COMMAND_SUPPORT dependency Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2016-04-25 11:30 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/gadget/f_fastboot.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index aaf7849..1f56975 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -28,6 +28,8 @@
 #include <dma.h>
 #include <fs.h>
 #include <libfile.h>
+#include <ubiformat.h>
+#include <stdlib.h>
 #include <file-list.h>
 #include <progress.h>
 #include <environment.h>
@@ -687,9 +689,12 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd
 	}
 
 	if (filetype == filetype_ubi) {
-		char *cmd;
 		int fd;
 		struct mtd_info_user meminfo;
+		struct ubiformat_args args = {
+			.yes = 1,
+			.image = FASTBOOT_TMPFILE,
+		};
 
 		fd = open(filename, O_RDONLY);
 		if (fd < 0)
@@ -701,13 +706,9 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd
 		if (ret)
 			goto copy;
 
-		cmd = asprintf("ubiformat -y -f %s %s", FASTBOOT_TMPFILE, filename);
-
 		fastboot_tx_print(f_fb, "INFOThis is an UBI image...");
 
-		ret = run_command(cmd);
-
-		free(cmd);
+		ret = ubiformat(meminfo.mtd, &args);
 
 		if (ret) {
 			fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret));
-- 
2.8.0.rc3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 5/5] usb: fastboot: drop CONFIG_COMMAND_SUPPORT dependency
  2016-04-25 11:30 Create and use C API for ubiformat Sascha Hauer
                   ` (3 preceding siblings ...)
  2016-04-25 11:30 ` [PATCH 4/5] usb: fastboot: Use C API for ubiformat Sascha Hauer
@ 2016-04-25 11:30 ` Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2016-04-25 11:30 UTC (permalink / raw)
  To: Barebox List

fastboot can run without command support. In this case we cannot
execute oem commands.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/gadget/Kconfig      | 1 +
 drivers/usb/gadget/f_fastboot.c | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 13a3e70..fefe2dd 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -45,6 +45,7 @@ config USB_GADGET_FASTBOOT
 	bool
 	select BANNER
 	depends on COMMAND_SUPPORT
+	select BOSCH_COMMON
 	prompt "Android Fastboot support"
 
 endif
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 1f56975..e83fa30 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -867,6 +867,11 @@ static void cb_oem_exec(struct usb_ep *ep, struct usb_request *req, const char *
 	struct f_fastboot *f_fb = req->context;
 	int ret;
 
+	if (!IS_ENABLED(CONFIG_COMMAND)) {
+		fastboot_tx_print(f_fb, "FAILno command support available");
+		return;
+	}
+
 	ret = run_command(cmd);
 	if (ret < 0)
 		fastboot_tx_print(f_fb, "FAIL%s", strerror(-ret));
-- 
2.8.0.rc3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-04-25 11:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-25 11:30 Create and use C API for ubiformat Sascha Hauer
2016-04-25 11:30 ` [PATCH 1/5] commands: ubiformat: Pass around context data Sascha Hauer
2016-04-25 11:30 ` [PATCH 2/5] commands: ubiformat: create separate function for ubiformat Sascha Hauer
2016-04-25 11:30 ` [PATCH 3/5] commands: ubiformat: move code to common/ Sascha Hauer
2016-04-25 11:30 ` [PATCH 4/5] usb: fastboot: Use C API for ubiformat Sascha Hauer
2016-04-25 11:30 ` [PATCH 5/5] usb: fastboot: drop CONFIG_COMMAND_SUPPORT dependency Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox