[PATCH 3/5] Check ONFI parameter page before using it.
kristof at sigsegv.be
kristof at sigsegv.be
Wed Nov 13 22:32:45 UTC 2013
From: Kristof Provost <kristof at sigsegv.be>
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
More information about the freebsd-embedded
mailing list