[PATCH] Add driver for M-sys / Sandisk diskonchip G4 nand flash

Ivan Djelic ivan.djelic at parrot.com
Wed Oct 12 14:49:03 EDT 2011


On Tue, Oct 11, 2011 at 08:17:22PM +0100, Mike Dunn wrote:
> On 10/11/2011 04:50 AM, Ivan Djelic wrote:
> >
> > After a more careful examination, I believe your hardware gives you
> > recv_ecc^calc_ecc
> 
> It might be a little more complicated.

Well, thanks to your ecc samples I have the answer now; the hardware does
provide recv_ecc^calc_ecc, with a little twist: a parity code in inserted into
data before performing BCH remainder computations.
Here is a more precise description:

writing algorithm:
-----------------
1. 512 bytes of data are sent to HW generator
2. 7 bytes of user data (oob[0] to oob[6]) are sent to HW generator
3. A Hamming (?) parity byte is generated (from oob[0]...oob[6]?) and sent to
   HW generator
4. The BCH engine completes its polynomial remainder computation on the above
   520 bytes

Note that the HW generator reads and writes bytes in reversed bit order.

I don't really know how the parity byte in step 3 is generated, or what its
purpose is; it may be there to allow oob reading without performing a full BCH
decode, but the code seems too small to me to protect anything in a useful way.
The nice thing is, we don't really need this code to perform BCH decoding.

Here is an updated version of my function emulating hw ecc:

static const uint8_t reverse8[256] = {
/* http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable */
#   define R2(n) n,     n + 2*64,     n + 1*64,     n + 3*64
#   define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16)
#   define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 )
    R6(0), R6(2), R6(1), R6(3)
};

static void emulate_docg4_hw(struct bch_control *bch, uint8_t *buf,
                             uint8_t *ecc_flash, uint8_t hamming)
{
        int i;
	uint8_t data[DOCG4_DATA_LEN];
        uint8_t ecc_buf[8] = {0};

	for (i = 0; i < DOCG4_DATA_LEN-1; i++)
	    data[i] = reverse8[buf[i]];
	data[DOCG4_DATA_LEN-1] = reverse8[hamming];

        encode_bch(bch, data, DOCG4_DATA_LEN, ecc_buf);

        printk("emulated ecc_buf = ");
        for (i = 0; i < 7; i++) {
                ecc_buf[i] = reverse8[ecc_buf[i]] ^ ecc_flash[i];
                printk("%02x", ecc_buf[i]);
        }
}

If you pass ecc_flash[]={0,0,0,0,0,0,0} to this function, and the proper parity
code corresponding to your data, you should get the same ecc bytes as what your
hardware generates on a write operation.
Note the new parameter 'hamming', required to perform BCH encoding.
Using this function on your samples:

- a page (520 bytes) filled with 0x00, except the first byte set to 0x01
  with hamming=0x01, emulate_docg4_hw() outputs the correct d47899c27e7c7f code

- a page (520 bytes) filled with 0xff, except the first byte set to 0x55
  with hamming=0x31, emulate_docg4_hw() outputs the correct 70f363ce4b969a code

In both cases, Hamming codes were found by brute force searching. Again, those
codes are not needed to perform decoding.

In my previous message, I provided a simplified docg4_correct_data() function
with the following piece of code:

        /* ----------------------- MODIFIED PART ------------------------- */
        /* reformat ecc */
        for (i = 0; i < 7; i++)
                doc->ecc_buf[i] = reverse8[doc->ecc_buf[i]];

        /* decode data and find errors */
        numerrs = decode_bch(doc->bch, NULL, DOCG4_DATA_LEN, NULL,
                             doc->ecc_buf, NULL, errorpos);
        if (numerrs == -EBADMSG) {
                printk(KERN_WARNING "docg4: "
                       "uncorrectable errors at offset %08x\n", page * 0x200);
                writew(0, docptr + DOCG4_END_OF_DATA);
                return -1;
        }

        /* fix the errors */
        for (i = 0; i < numerrs; i++) {
                errorpos[i] = (errorpos[i] & ~7)|(7-(errorpos[i] & 7));
                change_bit(errpos[i], (unsigned long *)buf);
        }
        /* -------------------------------------------------------------- */

I simulated bitflips on your data samples and verified that the code above
generates the same syndrome (and by consequence the same errorpos[] array) as
your function docg4_find_errbits().
Could you try this in your driver and tell me if it matches your errorpos[]
results ?

Thanks,
--
Ivan



More information about the linux-mtd mailing list