diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 41aaf7f266f11b36a82f073f41f383fc2810e948..dcccc197954fe5621ae8473b7eb56254647f2009 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -449,14 +449,40 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 	 *   0    1     2       3    4
 	 *   nand erase [clean] [off size]
 	 */
-	if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
+	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 o = clean ? 3 : 2;
-		int scrub = !strcmp(cmd, "scrub");
+		int scrub = !strncmp(cmd, "scrub", 5);
+		int part = 0;
+		int chip = 0;
+		int spread = 0;
+		int args = 2;
+
+		if (cmd[5] != 0) {
+			if (!strcmp(&cmd[5], ".spread")) {
+				spread = 1;
+			} else if (!strcmp(&cmd[5], ".part")) {
+				part = 1;
+				args = 1;
+			} else if (!strcmp(&cmd[5], ".chip")) {
+				chip = 1;
+				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: ", scrub ? "scrub" : "erase");
+		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) != 0)
 			return 1;
@@ -468,6 +494,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 		opts.length = size;
 		opts.jffs2  = clean;
 		opts.quiet  = quiet;
+		opts.spread = spread;
 
 		if (scrub) {
 			puts("Warning: "
@@ -648,11 +675,16 @@ U_BOOT_CMD(
 	"nand write - addr off|partition size\n"
 	"    read/write 'size' bytes starting at offset 'off'\n"
 	"    to/from memory address 'addr', skipping bad blocks.\n"
-	"nand erase [clean] [off size] - erase 'size' bytes from\n"
-	"    offset 'off' (entire device if not specified)\n"
+	"nand erase[.spread] [clean] [off [size]] - erase 'size' bytes "
+	"from offset 'off'\n"
+	"    With '.spread', erase enough for given file size, otherwise,\n"
+	"    'size' includes skipped bad blocks.\n"
+	"nand erase.part [clean] partition - erase entire mtd partition'\n"
+	"nand erase.chip [clean] - erase entire chip'\n"
 	"nand bad - show bad blocks\n"
 	"nand dump[.oob] off - dump page\n"
-	"nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
+	"nand scrub off size | scrub.part partition | scrub.chip\n"
+	"    really clean NAND erasing bad blocks (UNSAFE)\n"
 	"nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
 	"nand biterr off - make a bit error at offset (UNSAFE)"
 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 0f67790488bcdfdeaf43d6f94b388de41beb3c82..6a5dd372cc673baca0a5f077b77086c6d2d433fa 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -75,7 +75,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
 {
 	struct jffs2_unknown_node cleanmarker;
 	erase_info_t erase;
-	ulong erase_length;
+	unsigned long erase_length, erased_length; /* in blocks */
 	int bbtest = 1;
 	int result;
 	int percent_complete = -1;
@@ -84,13 +84,19 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
 	struct mtd_oob_ops oob_opts;
 	struct nand_chip *chip = meminfo->priv;
 
+	if ((opts->offset & (meminfo->writesize - 1)) != 0) {
+		printf("Attempt to erase non page aligned data\n");
+		return -1;
+	}
+
 	memset(&erase, 0, sizeof(erase));
 	memset(&oob_opts, 0, sizeof(oob_opts));
 
 	erase.mtd = meminfo;
 	erase.len  = meminfo->erasesize;
 	erase.addr = opts->offset;
-	erase_length = opts->length;
+	erase_length = lldiv(opts->length + meminfo->erasesize - 1,
+			     meminfo->erasesize);
 
 	cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
 	cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
@@ -114,15 +120,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
 		priv_nand->bbt = NULL;
 	}
 
-	if (erase_length < meminfo->erasesize) {
-		printf("Warning: Erase size 0x%08lx smaller than one "	\
-		       "erase block 0x%08x\n",erase_length, meminfo->erasesize);
-		printf("         Erasing 0x%08x instead\n", meminfo->erasesize);
-		erase_length = meminfo->erasesize;
-	}
-
-	for (;
-	     erase.addr < opts->offset + erase_length;
+	for (erased_length = 0;
+	     erased_length < erase_length;
 	     erase.addr += meminfo->erasesize) {
 
 		WATCHDOG_RESET ();
@@ -135,6 +134,10 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
 					       "0x%08llx                 "
 					       "                         \n",
 					       erase.addr);
+
+				if (!opts->spread)
+					erased_length++;
+
 				continue;
 
 			} else if (ret < 0) {
@@ -145,6 +148,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
 			}
 		}
 
+		erased_length++;
+
 		result = meminfo->erase(meminfo, &erase);
 		if (result != 0) {
 			printf("\n%s: MTD Erase failure: %d\n",
@@ -171,9 +176,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
 		}
 
 		if (!opts->quiet) {
-			unsigned long long n =(unsigned long long)
-				(erase.addr + meminfo->erasesize - opts->offset)
-				* 100;
+			unsigned long long n = erased_length * 100ULL;
 			int percent;
 
 			do_div(n, erase_length);
diff --git a/include/nand.h b/include/nand.h
index 8bdf4191a6db159222e83e38ad433fc07f428122..a4524113d00e60f7f6b30acc4c4fff263fc39e62 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -98,13 +98,16 @@ struct nand_read_options {
 typedef struct nand_read_options nand_read_options_t;
 
 struct nand_erase_options {
-	ulong length;		/* number of bytes to erase */
-	ulong offset;		/* first address in NAND to erase */
+	loff_t length;		/* number of bytes to erase */
+	loff_t offset;		/* first address in NAND to erase */
 	int quiet;		/* don't display progress messages */
 	int jffs2;		/* if true: format for jffs2 usage
 				 * (write appropriate cleanmarker blocks) */
 	int scrub;		/* if true, really clean NAND by erasing
 				 * bad blocks (UNSAFE) */
+
+	/* Don't include skipped bad blocks in size to be erased */
+	int spread;
 };
 
 typedef struct nand_erase_options nand_erase_options_t;