env_nand.c: support falling back to redundant env when writing
Without this patch, when the currently chosen environment to be written has bad blocks, saveenv fails completely. Instead, when there is redundant environment fall back to the other copy. Environment reading needs no adjustment, as the fallback logic for incomplete writes applies to this case as well. Signed-off-by: Phil Sutter <phil.sutter@viprinet.com>
This commit is contained in:
		
							parent
							
								
									47b6dad319
								
							
						
					
					
						commit
						2b26201a2a
					
				|  | @ -152,72 +152,57 @@ int writeenv(size_t offset, u_char *buf) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_ENV_OFFSET_REDUND | struct env_location { | ||||||
| static unsigned char env_flags; | 	const char *name; | ||||||
|  | 	const nand_erase_options_t erase_opts; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| int saveenv(void) | static int erase_and_write_env(const struct env_location *location, | ||||||
|  | 		u_char *env_new) | ||||||
| { | { | ||||||
| 	env_t	env_new; | 	int ret = 0; | ||||||
| 	ssize_t	len; |  | ||||||
| 	char	*res; |  | ||||||
| 	int	ret = 0; |  | ||||||
| 	nand_erase_options_t nand_erase_options; |  | ||||||
| 
 | 
 | ||||||
| 	memset(&nand_erase_options, 0, sizeof(nand_erase_options)); | 	printf("Erasing %s...\n", location->name); | ||||||
| 	nand_erase_options.length = CONFIG_ENV_RANGE; | 	if (nand_erase_opts(&nand_info[0], &location->erase_opts)) | ||||||
| 
 |  | ||||||
| 	if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) |  | ||||||
| 		return 1; | 		return 1; | ||||||
| 
 | 
 | ||||||
| 	res = (char *)&env_new.data; | 	printf("Writing to %s... ", location->name); | ||||||
| 	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); | 	ret = writeenv(location->erase_opts.offset, env_new); | ||||||
| 	if (len < 0) { | 	puts(ret ? "FAILED!\n" : "OK\n"); | ||||||
| 		error("Cannot export environment: errno = %d\n", errno); |  | ||||||
| 		return 1; |  | ||||||
| 	} |  | ||||||
| 	env_new.crc	= crc32(0, env_new.data, ENV_SIZE); |  | ||||||
| 	env_new.flags	= ++env_flags; /* increase the serial */ |  | ||||||
| 
 |  | ||||||
| 	if (gd->env_valid == 1) { |  | ||||||
| 		puts("Erasing redundant NAND...\n"); |  | ||||||
| 		nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; |  | ||||||
| 		if (nand_erase_opts(&nand_info[0], &nand_erase_options)) |  | ||||||
| 			return 1; |  | ||||||
| 
 |  | ||||||
| 		puts("Writing to redundant NAND... "); |  | ||||||
| 		ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new); |  | ||||||
| 	} else { |  | ||||||
| 		puts("Erasing NAND...\n"); |  | ||||||
| 		nand_erase_options.offset = CONFIG_ENV_OFFSET; |  | ||||||
| 		if (nand_erase_opts(&nand_info[0], &nand_erase_options)) |  | ||||||
| 			return 1; |  | ||||||
| 
 |  | ||||||
| 		puts("Writing to NAND... "); |  | ||||||
| 		ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new); |  | ||||||
| 	} |  | ||||||
| 	if (ret) { |  | ||||||
| 		puts("FAILED!\n"); |  | ||||||
| 		return 1; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	puts("done\n"); |  | ||||||
| 
 |  | ||||||
| 	gd->env_valid = gd->env_valid == 2 ? 1 : 2; |  | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| #else /* ! CONFIG_ENV_OFFSET_REDUND */ | 
 | ||||||
|  | #ifdef CONFIG_ENV_OFFSET_REDUND | ||||||
|  | static unsigned char env_flags; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| int saveenv(void) | int saveenv(void) | ||||||
| { | { | ||||||
| 	int	ret = 0; | 	int	ret = 0; | ||||||
| 	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); | 	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); | ||||||
| 	ssize_t	len; | 	ssize_t	len; | ||||||
| 	char	*res; | 	char	*res; | ||||||
| 	nand_erase_options_t nand_erase_options; | 	int	env_idx = 0; | ||||||
|  | 	static const struct env_location location[] = { | ||||||
|  | 		{ | ||||||
|  | 			.name = "NAND", | ||||||
|  | 			.erase_opts = { | ||||||
|  | 				.length = CONFIG_ENV_RANGE, | ||||||
|  | 				.offset = CONFIG_ENV_OFFSET, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | #ifdef CONFIG_ENV_OFFSET_REDUND | ||||||
|  | 		{ | ||||||
|  | 			.name = "redundant NAND", | ||||||
|  | 			.erase_opts = { | ||||||
|  | 				.length = CONFIG_ENV_RANGE, | ||||||
|  | 				.offset = CONFIG_ENV_OFFSET_REDUND, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | #endif | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| 	memset(&nand_erase_options, 0, sizeof(nand_erase_options)); |  | ||||||
| 	nand_erase_options.length = CONFIG_ENV_RANGE; |  | ||||||
| 	nand_erase_options.offset = CONFIG_ENV_OFFSET; |  | ||||||
| 
 | 
 | ||||||
| 	if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) | 	if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) | ||||||
| 		return 1; | 		return 1; | ||||||
|  | @ -228,22 +213,29 @@ int saveenv(void) | ||||||
| 		error("Cannot export environment: errno = %d\n", errno); | 		error("Cannot export environment: errno = %d\n", errno); | ||||||
| 		return 1; | 		return 1; | ||||||
| 	} | 	} | ||||||
| 	env_new->crc = crc32(0, env_new->data, ENV_SIZE); | 	env_new->crc   = crc32(0, env_new->data, ENV_SIZE); | ||||||
|  | #ifdef CONFIG_ENV_OFFSET_REDUND | ||||||
|  | 	env_new->flags = ++env_flags; /* increase the serial */ | ||||||
|  | 	env_idx = (gd->env_valid == 1); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	puts("Erasing Nand...\n"); | 	ret = erase_and_write_env(&location[env_idx], (u_char *)env_new); | ||||||
| 	if (nand_erase_opts(&nand_info[0], &nand_erase_options)) | #ifdef CONFIG_ENV_OFFSET_REDUND | ||||||
| 		return 1; | 	if (!ret) { | ||||||
| 
 | 		/* preset other copy for next write */ | ||||||
| 	puts("Writing to Nand... "); | 		gd->env_valid = gd->env_valid == 2 ? 1 : 2; | ||||||
| 	if (writeenv(CONFIG_ENV_OFFSET, (u_char *)env_new)) { | 		return ret; | ||||||
| 		puts("FAILED!\n"); |  | ||||||
| 		return 1; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	puts("done\n"); | 	env_idx = (env_idx + 1) & 1; | ||||||
|  | 	ret = erase_and_write_env(&location[env_idx], (u_char *)env_new); | ||||||
|  | 	if (!ret) | ||||||
|  | 		printf("Warning: primary env write failed," | ||||||
|  | 				" redundancy is lost!\n"); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| #endif /* CONFIG_ENV_OFFSET_REDUND */ |  | ||||||
| #endif /* CMD_SAVEENV */ | #endif /* CMD_SAVEENV */ | ||||||
| 
 | 
 | ||||||
| int readenv(size_t offset, u_char *buf) | int readenv(size_t offset, u_char *buf) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue