From patchwork Fri Jul 19 10:20:26 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Sutter X-Patchwork-Id: 260233 X-Patchwork-Delegate: scottwood@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 50ED22C0079 for ; Fri, 19 Jul 2013 20:20:59 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 842BB4A02D; Fri, 19 Jul 2013 12:20:57 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Ys1VjbmOYpoq; Fri, 19 Jul 2013 12:20:57 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B64D14A021; Fri, 19 Jul 2013 12:20:52 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2089F4A021 for ; Fri, 19 Jul 2013 12:20:48 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ebOlaKZGOf41 for ; Fri, 19 Jul 2013 12:20:42 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 BL_NJABL=ERR(-1.5) (only DNSBL check requested) Received: from zimbra.vipri.net (zimbra.vipri.net [89.207.250.15]) by theia.denx.de (Postfix) with ESMTP id 363584A020 for ; Fri, 19 Jul 2013 12:20:34 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by zimbra.vipri.net (Postfix) with ESMTP id AE49710001FF; Fri, 19 Jul 2013 12:14:01 +0200 (CEST) X-Virus-Scanned: amavisd-new at zimbra.vipri.net Received: from zimbra.vipri.net ([127.0.0.1]) by localhost (zimbra.vipri.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id oB5JrE88zdD7; Fri, 19 Jul 2013 12:14:01 +0200 (CEST) Received: from phil.computerman.de (host-089-207-255-234.vipri.net [89.207.255.234]) by zimbra.vipri.net (Postfix) with ESMTPSA id DEDC710001F4; Fri, 19 Jul 2013 12:14:00 +0200 (CEST) From: Phil Sutter To: u-boot@lists.denx.de Date: Fri, 19 Jul 2013 12:20:26 +0200 Message-Id: <1374229226-30392-1-git-send-email-phil.sutter@viprinet.com> X-Mailer: git-send-email 1.8.2.1 In-Reply-To: <20130719100943.GB18247@philter.vipri.net> References: <20130719100943.GB18247@philter.vipri.net> Cc: Scott Wood Subject: [U-Boot] [PATCH] env_nand.c: support falling back to redundant env when writing X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 --- Changes since V1: - Print status message for each of the redundant copies when writing, so the error message for any first failed attempt does not confuse that much. Changes since V2: - Checkpatch-compliance: - do not typedef struct env_location - avoid assignments in conditionals - some minor formatting corrections - make location array static const Changes since V3: - constify field 'erase_opts' in struct env_location, no need to assign to it at run-time - drop unnecessary field 'offset' in struct env_location - function 'erase_and_write_env' must take passed struct env_location as const - declare a global var 'env_flags' only if CONFIG_ENV_OFFSET_REDUND is defined - warn if first attempt to write env failed --- common/env_nand.c | 116 +++++++++++++++++++++++++----------------------------- 1 file changed, 54 insertions(+), 62 deletions(-) diff --git a/common/env_nand.c b/common/env_nand.c index b745822..db7da37 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -168,72 +168,57 @@ int writeenv(size_t offset, u_char *buf) return 0; } -#ifdef CONFIG_ENV_OFFSET_REDUND -static unsigned char env_flags; +struct env_location { + 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; - ssize_t len; - char *res; - int ret = 0; - nand_erase_options_t nand_erase_options; + int ret = 0; - memset(&nand_erase_options, 0, sizeof(nand_erase_options)); - nand_erase_options.length = CONFIG_ENV_RANGE; - - if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) - return 1; - - res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); - if (len < 0) { - 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"); + printf("Erasing %s...\n", location->name); + if (nand_erase_opts(&nand_info[0], &location->erase_opts)) return 1; - } - - puts("done\n"); - gd->env_valid = gd->env_valid == 2 ? 1 : 2; + printf("Writing to %s... ", location->name); + ret = writeenv(location->erase_opts.offset, env_new); + puts(ret ? "FAILED!\n" : "OK\n"); return ret; } -#else /* ! CONFIG_ENV_OFFSET_REDUND */ + +#ifdef CONFIG_ENV_OFFSET_REDUND +static unsigned char env_flags; +#endif + int saveenv(void) { int ret = 0; ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); ssize_t len; 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) return 1; @@ -244,22 +229,29 @@ int saveenv(void) error("Cannot export environment: errno = %d\n", errno); return 1; } - env_new->crc = crc32(0, env_new->data, ENV_SIZE); - - puts("Erasing Nand...\n"); - if (nand_erase_opts(&nand_info[0], &nand_erase_options)) - return 1; + 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("Writing to Nand... "); - if (writeenv(CONFIG_ENV_OFFSET, (u_char *)env_new)) { - puts("FAILED!\n"); - return 1; + ret = erase_and_write_env(&location[env_idx], (u_char *)env_new); +#ifdef CONFIG_ENV_OFFSET_REDUND + if (!ret) { + /* preset other copy for next write */ + gd->env_valid = gd->env_valid == 2 ? 1 : 2; + return ret; } - 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; } -#endif /* CONFIG_ENV_OFFSET_REDUND */ #endif /* CMD_SAVEENV */ int readenv(size_t offset, u_char *buf)