From owner-freebsd-embedded@FreeBSD.ORG Wed Nov 13 22:32:45 2013 Return-Path: Delivered-To: freebsd-embedded@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 4E38A4C9; Wed, 13 Nov 2013 22:32:45 +0000 (UTC) Received: from venus.codepro.be (venus.codepro.be [IPv6:2a01:4f8:162:1127::2]) (using TLSv1 with cipher ADH-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 1491725CA; Wed, 13 Nov 2013 22:32:45 +0000 (UTC) Received: from adrastea.jupiter.sigsegv.be (unknown [IPv6:2a02:1811:2000:701:1b:9fff:fe00:160b]) by venus.codepro.be (Postfix) with ESMTPSA id BD0789B2A; Wed, 13 Nov 2013 23:32:43 +0100 (CET) Received: from sigsegv.be (unknown [10.0.2.251]) by adrastea.jupiter.sigsegv.be (Postfix) with ESMTP id DAAB14161; Wed, 13 Nov 2013 23:32:42 +0100 (CET) From: kristof@sigsegv.be To: Ian Lepore Subject: [PATCH 3/5] Check ONFI parameter page before using it. Date: Wed, 13 Nov 2013 23:32:38 +0100 Message-Id: <1384381960-98851-4-git-send-email-kristof@sigsegv.be> X-Mailer: git-send-email 1.7.10.3 In-Reply-To: <1384381960-98851-1-git-send-email-kristof@sigsegv.be> References: <1383782353.31172.183.camel@revolution.hippie.lan> <1384381960-98851-1-git-send-email-kristof@sigsegv.be> Cc: Grzegorz Bernacki , freebsd-embedded@FreeBSD.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Nov 2013 22:32:45 -0000 From: Kristof Provost The ONFI spec states that at least two bytes of the signature ("ONFI") must be present, and the CRC must be correct to have a valid parameter page. If the page is not valid there are at least two backup pages where the data can also be found. --- sys/dev/nand/nand_generic.c | 55 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/sys/dev/nand/nand_generic.c b/sys/dev/nand/nand_generic.c index 2e78ab6..4ee8fdc 100644 --- a/sys/dev/nand/nand_generic.c +++ b/sys/dev/nand/nand_generic.c @@ -319,10 +319,31 @@ check_fail(device_t nandbus) return (0); } +static uint16_t +onfi_crc(const void *buf, size_t buflen) +{ + int i, j; + uint16_t crc; + const uint8_t *bufptr; + + bufptr = buf; + crc = 0x4f4e; + for (j = 0; j < buflen; j++) { + crc ^= *bufptr++ << 8; + for (i = 0; i < 8; i++) + if (crc & 0x8000) + crc = (crc << 1) ^ 0x8005; + else + crc <<= 1; + } + return crc; +} + static int onfi_read_parameter(struct nand_chip *chip, struct onfi_params *params) { device_t nandbus; + int found, sigcount, trycopy; nand_debug(NDBG_GEN,"read parameter"); @@ -339,16 +360,32 @@ onfi_read_parameter(struct nand_chip *chip, struct onfi_params *params) if (NANDBUS_START_COMMAND(nandbus)) return (ENXIO); - NANDBUS_READ_BUFFER(nandbus, params, sizeof(struct onfi_params)); - - if (memcmp(params->signature, "ONFI", sizeof(params->signature))) { - device_printf(chip->dev, "Error: bad signature\n"); - return (ENXIO); + /* + * XXX Bogus DELAY, we really need a nandbus_wait_ready() here, but it's + * not accessible from here (static to nandbus). + */ + DELAY(1000); + + /* + * The ONFI spec mandates a minimum of three copies of the parameter + * data, so loop up to 3 times trying to find good data. Each copy is + * validated by a signature of "ONFI" and a crc. There is a very strange + * rule that the signature is valid if any 2 of the 4 bytes are correct. + */ + for (found= 0, trycopy = 0; !found && trycopy < 3; trycopy++) { + NANDBUS_READ_BUFFER(nandbus, params, sizeof(struct onfi_params)); + sigcount = params->signature[0] == 'O'; + sigcount += params->signature[1] == 'N'; + sigcount += params->signature[2] == 'F'; + sigcount += params->signature[3] == 'I'; + if (sigcount < 2) + continue; + if (onfi_crc(params, 254) != params->crc) + continue; + found = 1; } - - /* TODO */ - /* Check CRC */ - /* Use redundant page if necessary */ + if (!found) + return (ENXIO); return (0); } -- 1.7.10.3