diff options
Diffstat (limited to 'libnandfs')
| -rw-r--r-- | libnandfs/NOTICE | 5 | ||||
| -rw-r--r-- | libnandfs/calcformat.c | 24 | ||||
| -rw-r--r-- | libnandfs/correctauxilliary.c | 81 | ||||
| -rw-r--r-- | libnandfs/ecc.c | 98 | ||||
| -rw-r--r-- | libnandfs/eraseblock.c | 50 | ||||
| -rw-r--r-- | libnandfs/extracttags.c | 26 | ||||
| -rw-r--r-- | libnandfs/findfreeblock.c | 28 | ||||
| -rw-r--r-- | libnandfs/formatblock.c | 57 | ||||
| -rw-r--r-- | libnandfs/getblockstatus.c | 27 | ||||
| -rw-r--r-- | libnandfs/hamming31_26.c | 62 | ||||
| -rw-r--r-- | libnandfs/init.c | 102 | ||||
| -rw-r--r-- | libnandfs/local.h | 51 | ||||
| -rw-r--r-- | libnandfs/markblockbad.c | 42 | ||||
| -rw-r--r-- | libnandfs/mkfile | 33 | ||||
| -rw-r--r-- | libnandfs/open.c | 253 | ||||
| -rw-r--r-- | libnandfs/readblock.c | 36 | ||||
| -rw-r--r-- | libnandfs/readpage.c | 52 | ||||
| -rw-r--r-- | libnandfs/readpageauxilliary.c | 35 | ||||
| -rw-r--r-- | libnandfs/reformatblock.c | 34 | ||||
| -rw-r--r-- | libnandfs/setget.c | 101 | ||||
| -rw-r--r-- | libnandfs/updatepage.c | 38 | ||||
| -rw-r--r-- | libnandfs/writeblock.c | 47 | ||||
| -rw-r--r-- | libnandfs/writepageauxilliary.c | 33 |
23 files changed, 1315 insertions, 0 deletions
diff --git a/libnandfs/NOTICE b/libnandfs/NOTICE new file mode 100644 index 00000000..d8e20618 --- /dev/null +++ b/libnandfs/NOTICE @@ -0,0 +1,5 @@ +Developed 2002, 2003 by Vita Nuova Holdings Limited. +Copyright © 2002, 2003 Vita Nuova Holdings Limited. + +The source and binary code for libnandfs may be used only as part of Inferno, +unless otherwise agreed with Vita Nuova. diff --git a/libnandfs/calcformat.c b/libnandfs/calcformat.c new file mode 100644 index 00000000..498427f5 --- /dev/null +++ b/libnandfs/calcformat.c @@ -0,0 +1,24 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +int +nandfscalcformat(Nandfs *nandfs, long base, long limit, long bootsize, long *baseblock, long *limitblock, long *bootblocks) +{ + *baseblock = (base + nandfs->rawblocksize - 1) / nandfs->rawblocksize; + if (limit == 0) + *limitblock = nandfs->limitblock; + else + *limitblock = limit / nandfs->rawblocksize; + *bootblocks = (bootsize + nandfs->rawblocksize - 1) / nandfs->rawblocksize; + if (*bootblocks < 3) + *bootblocks = 3; + /* sanity checks */ + if (*limitblock > nandfs->limitblock + || *baseblock < nandfs->baseblock + || *bootblocks > nandfs->limitblock - nandfs->baseblock) + return 0; + return 1; +} + diff --git a/libnandfs/correctauxilliary.c b/libnandfs/correctauxilliary.c new file mode 100644 index 00000000..510aeac4 --- /dev/null +++ b/libnandfs/correctauxilliary.c @@ -0,0 +1,81 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +static int +hammingdistance(uchar a, uchar b) +{ + uchar c; + int i, k; + if (a == b) + return 0; + c = a ^ b; + for (i = 0x80, k = 0; i; i >>= 1) + if (c & i) + k++; + return k; +} + +static int +allones(uchar *data, int len) +{ + while (len-- > 0) + if (*data++ != 0xff) + return 0; + return 1; +} + +LogfsLowLevelReadResult +_nandfscorrectauxiliary(NandfsAuxiliary *hdr) +{ + /* + * correct single bit errors, detect more than 1, in + * tag, signature + * TODO: add nerase and path protection + */ + LogfsLowLevelReadResult e; + int x; + int min, minx; + + e = LogfsLowLevelReadResultOk; + + min = 8; + minx = 0; + for (x = 0; x < _nandfsvalidtagscount; x++) { + int d = hammingdistance(hdr->tag, _nandfsvalidtags[x]); + if (d < min) { + min = d; + minx = x; + if (d == 0) + break; + } + } + if (min == 1) { + hdr->tag = _nandfsvalidtags[minx]; + e = LogfsLowLevelReadResultSoftError; + } + else if (min > 1) + e = LogfsLowLevelReadResultHardError; + else { + if (hdr->tag != LogfsTnone) { + ulong tmp = getbig4(hdr->parth); + if (tmp != 0xfffffffff && _nandfshamming31_26correct(&tmp)) { + putbig4(hdr->parth, tmp); + if (e != LogfsLowLevelReadResultOk) + e = LogfsLowLevelReadResultSoftError; + } + tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw); + if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) { + putbig2(hdr->nerasemagicmsw, tmp >> 16); + putbig2(hdr->nerasemagiclsw, tmp); + if (e != LogfsLowLevelReadResultOk) + e = LogfsLowLevelReadResultSoftError; + } + } + else if (allones((uchar *)hdr, sizeof(*hdr))) + e = LogfsLowLevelReadResultAllOnes; + } + + return e; +} diff --git a/libnandfs/ecc.c b/libnandfs/ecc.c new file mode 100644 index 00000000..1cd86d20 --- /dev/null +++ b/libnandfs/ecc.c @@ -0,0 +1,98 @@ +#include "lib9.h" +#include "nandecc.h" + +static uchar ecctab[] = { + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, +}; + +ulong +nandecc(uchar *buf) +{ + int cp, zeros, ones, im; + int lp, om; + int i; + + cp = 0xff; + zeros = 0xff; + ones = 0xff; + for (i = 0; i < 256; i++) { + int tabent = ecctab[buf[i]]; + cp ^= tabent; + if (tabent & 1) { + zeros ^= ~i; + ones ^= i; + } + } + lp = 0; + for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) { + if (ones & im) + lp |= om; + om >>= 1; + if (zeros & im) + lp |= om; + } + return (((cp & 0xff) | 3) << 16) | lp; +} + +#define CORRECTABLEMASK 0x545555 + +NandEccError +nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad) +{ + ulong xorecc; + ulong mask; + int k; + + if (calcecc == *storedecc) + return NandEccErrorGood; + if (reportbad) + print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n", calcecc, *storedecc); + xorecc = calcecc ^ *storedecc; + if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) { + ulong imask; + ushort out; + ushort omask; + int line, col; + + for (imask = 0x800000, omask = 0x800, out = 0; imask; imask >>= 2, omask >>= 1) { + if (xorecc & imask) + out |= omask; + } + line = out & 0xff; + col = out >> 9; + if (reportbad) + print("nandecccorrect: single bit error line %d col %d\n", line, col); + buf[line] ^= (1 << col); + *storedecc = calcecc; + return NandEccErrorOneBit; + } + for (mask = 0x800000, k = 0; mask; mask >>= 1) + if (mask & xorecc) + k++; + if (k == 1) { + if (reportbad) + print("nandecccorrect: single bit error in ecc\n"); + // assume the stored ecc was wrong + *storedecc = calcecc; + return NandEccErrorOneBitInEcc; + } + if (reportbad) + print("nandecccorrect: 2 bit error\n"); + return NandEccErrorBad; +} + diff --git a/libnandfs/eraseblock.c b/libnandfs/eraseblock.c new file mode 100644 index 00000000..2ecd490f --- /dev/null +++ b/libnandfs/eraseblock.c @@ -0,0 +1,50 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +char * +nandfseraseblock(Nandfs *nandfs, long block, void **llsavep, int *markedbad) +{ + NandfsBlockData *d; + char *errmsg; + + if (markedbad) + *markedbad = 0; + + errmsg = (*nandfs->erase)(nandfs->magic, nandfs->rawblocksize * (nandfs->baseblock + block)); + if (errmsg) { + if (nandfs->blockdata) { + d = &nandfs->blockdata[block]; + d->tag = LogfsTworse; + nandfs->worseblocks = 1; + } + if (strcmp(errmsg, Eio) != 0) + return errmsg; + if (markedbad) { + *markedbad = 1; + errmsg = nandfsmarkblockbad(nandfs, block); + if (strcmp(errmsg, Eio) != 0) + return errmsg; + return nil; + } + return errmsg; + } + + if (nandfs->blockdata) { + ulong *llsave; + d = &nandfs->blockdata[block]; + if (llsavep) { + llsave = nandfsrealloc(nil, sizeof(ulong)); + if (llsave == nil) + return Enomem; + *llsave = d->nerase; + *llsavep = llsave; + } + d->tag = 0xff; + d->path = NandfsPathMask; + d->nerase = NandfsNeraseMask; + } + return nil; +} + diff --git a/libnandfs/extracttags.c b/libnandfs/extracttags.c new file mode 100644 index 00000000..be3fc2da --- /dev/null +++ b/libnandfs/extracttags.c @@ -0,0 +1,26 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +void +_nandfsextracttags(NandfsAuxiliary *hdr, NandfsTags *tags) +{ + ulong tmp; + tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw); + if (tmp == 0xffffffff) { + tags->nerase = 0xffffffff; + tags->magic = 0xff; + } + else { + tags->nerase = (tmp >> 6) & 0x3ffff; + tags->magic = tmp >> 24; + } + tmp = getbig4(hdr->parth); + if (tmp != 0xffffffff) + tags->path = tmp >> 6; + else + tags->path = 0xffffffff; + tags->tag = hdr->tag; +} + diff --git a/libnandfs/findfreeblock.c b/libnandfs/findfreeblock.c new file mode 100644 index 00000000..e17f729a --- /dev/null +++ b/libnandfs/findfreeblock.c @@ -0,0 +1,28 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +long +nandfsfindfreeblock(Nandfs *nandfs, long *freeblocksp) +{ + long bestnewblock; + long bestnerase; + long i; + + if (freeblocksp) + *freeblocksp = 0; + for (i = 0, bestnewblock = -1, bestnerase = 0x7fffffff; i < nandfs->ll.blocks; i++) { + long nerase; + if (nandfsgettag(nandfs, i) == LogfsTnone) { + if (freeblocksp) { + (*freeblocksp)++; + } + if ((nerase = nandfsgetnerase(nandfs, i)) < bestnerase) { + bestnewblock = i; + bestnerase = nerase; + } + } + } + return bestnewblock; +} diff --git a/libnandfs/formatblock.c b/libnandfs/formatblock.c new file mode 100644 index 00000000..8f37e2c9 --- /dev/null +++ b/libnandfs/formatblock.c @@ -0,0 +1,57 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +char * +nandfsformatblock(Nandfs *nandfs, long absblock, uchar tag, ulong path, long baseblock, long sizeinblocks, int xcount, long *xdata, void *llsave, int *markedbad) +{ + int page; + char *rv; + NandfsTags t; + int ppb; + + if (markedbad) + *markedbad = 0; + + t.tag = tag; + t.magic = LogfsMagic; + t.nerase = *(ulong *)llsave < NandfsNeraseMask ? *(ulong *)llsave + 1 : 1; + + ppb = 1 << nandfs->ll.l2pagesperblock; + for (page = 0, rv = nil; rv == nil && page < ppb; page++) { + if (tag == LogfsTboot && page > 0 && page < xcount + 3) { + switch (page) { + case 1: + t.path = baseblock; + break; + case 2: + t.path = sizeinblocks; + break; + default: + t.path = xdata[page - 3]; + break; + } + } + else + t.path = path; + rv = nandfswritepageauxiliary(nandfs, &t, absblock, page); + if (rv) + break; + } + + if (rv) { + if (strcmp(rv, Eio) != 0) + return rv; + if (markedbad) { + *markedbad = 1; + rv = nandfsmarkabsblockbad(nandfs, absblock); + if (strcmp(rv, Eio) != 0) + return rv; + return nil; + } + return rv; + } + + return nil; +} diff --git a/libnandfs/getblockstatus.c b/libnandfs/getblockstatus.c new file mode 100644 index 00000000..0ebaf5e1 --- /dev/null +++ b/libnandfs/getblockstatus.c @@ -0,0 +1,27 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +char * +nandfsgetblockstatus(Nandfs *nandfs, long absblock, int *magicfound, void **llsavep, LogfsLowLevelReadResult *result) +{ + NandfsTags tags; + char *errmsg; + ulong *llsave; + + errmsg = nandfsreadpageauxiliary(nandfs, &tags, absblock, 0, 1, result); + + *magicfound = tags.magic == LogfsMagic; + + if (llsavep) { + llsave = nandfsrealloc(nil, sizeof(ulong)); + if (llsave == nil) + return Enomem; + *llsave = tags.nerase; + *llsavep = llsave; + } + + return errmsg; +} + diff --git a/libnandfs/hamming31_26.c b/libnandfs/hamming31_26.c new file mode 100644 index 00000000..a94262b7 --- /dev/null +++ b/libnandfs/hamming31_26.c @@ -0,0 +1,62 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" + +static unsigned long row4 = 0x001fffc0; +static unsigned long row3 = 0x0fe03fc0; +static unsigned long row2 = 0x71e3c3c0; +static unsigned long row1 = 0xb66cccc0; +static unsigned long row0 = 0xdab55540; + +static char map[] = { + -5, -4, 0, -3, 1, 2, 3, -2, + 4, 5, 6, 7, 8, 9, 10, -1, 11, + 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, +}; + +#define mashbits(rown) \ + c = (in) & (rown); \ + c ^= c >> 16; \ + c ^= c >> 8; \ + c ^= c >> 4; \ + c ^= c >> 2; \ + c = (c ^ (c >> 1)) & 1; \ + +static uchar +_nandfshamming31_26calcparity(ulong in) +{ + ulong c; + uchar out; + mashbits(row4); out = c; + mashbits(row3); out = (out << 1) | c; + mashbits(row2); out = (out << 1) | c; + mashbits(row1); out = (out << 1) | c; + mashbits(row0); out = (out << 1) | c; + return out; +} + +ulong +_nandfshamming31_26calc(ulong in) +{ + in &= 0xffffffc0; + return in | _nandfshamming31_26calcparity(in); +} + +int +_nandfshamming31_26correct(ulong *in) +{ + uchar eparity, parity; + ulong e; + eparity = _nandfshamming31_26calcparity(*in); + parity = (*in) & 0x1f; + e = eparity ^ parity; + if (e == 0) + return 0; + e--; + if (map[e] < 0) + return 1; // error in parity bits + e = map[e]; + *in ^= 1 << (31 - e); + return 1; +} diff --git a/libnandfs/init.c b/libnandfs/init.c new file mode 100644 index 00000000..ebfd6a67 --- /dev/null +++ b/libnandfs/init.c @@ -0,0 +1,102 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +uchar _nandfsvalidtags[] = { + LogfsTnone, + LogfsTboot, + LogfsTlog, + LogfsTdata, +}; + +int _nandfsvalidtagscount = nelem(_nandfsvalidtags); + +static int +l2(long n) +{ + int i; + for (i = 0; i < 32; i++) + if ((1 << i) >= n) + return i; + return 0; +} + +char * +nandfsinit(void *magic, long rawsize, long rawblocksize, + char *(*read)(void *magic, void *buf, long nbytes, ulong offset), + char *(*write)(void *magic, void *buf, long nbytes, ulong offset), + char *(*erase)(void *magic, long blockaddr), + char *(*sync)(void *magic), + LogfsLowLevel **llp) +{ + Nandfs *nandfs; + nandfs = nandfsrealloc(nil, sizeof(*nandfs)); + if (nandfs == nil) + return Enomem; + if (rawblocksize % NandfsFullSize) + return "unsupported block size"; + if (rawsize % rawblocksize) + return "size not multiple of block size"; + nandfs->read = read; + nandfs->write = write; + nandfs->erase = erase; + nandfs->sync = sync; + nandfs->magic = magic; + nandfs->limitblock = rawsize / rawblocksize; +//print("rawsize %ld\n", rawsize); +//print("rawblocksize %ld\n", rawblocksize); +//print("limitblock %ld\n", nandfs->limitblock); + nandfs->rawblocksize = rawblocksize; + /* fill in upper interface */ + nandfs->ll.pathbits = NandfsPathBits; + nandfs->ll.blocks = 0; + nandfs->ll.l2pagesize = NandfsL2PageSize; + nandfs->ll.l2pagesperblock = l2(rawblocksize / NandfsFullSize); + nandfs->ll.open = (LOGFSOPENFN *)nandfsopen; + nandfs->ll.getblocktag = (LOGFSGETBLOCKTAGFN *)nandfsgettag; + nandfs->ll.setblocktag = (LOGFSSETBLOCKTAGFN *)nandfssettag; + nandfs->ll.getblockpath = (LOGFSGETBLOCKPATHFN *)nandfsgetpath; + nandfs->ll.setblockpath = (LOGFSSETBLOCKPATHFN *)nandfssetpath; + nandfs->ll.getblockpartialformatstatus = (LOGFSGETBLOCKPARTIALFORMATSTATUSFN *)nandfsgetblockpartialformatstatus; + nandfs->ll.findfreeblock = (LOGFSFINDFREEBLOCKFN *)nandfsfindfreeblock; + nandfs->ll.readpagerange = (LOGFSREADPAGERANGEFN *)nandfsreadpagerange; + nandfs->ll.writepage = (LOGFSWRITEPAGEFN *)nandfswritepage; + nandfs->ll.readblock = (LOGFSREADBLOCKFN *)nandfsreadblock; + nandfs->ll.writeblock = (LOGFSWRITEBLOCKFN *)nandfswriteblock; + nandfs->ll.eraseblock = (LOGFSERASEBLOCKFN *)nandfseraseblock; + nandfs->ll.formatblock = (LOGFSFORMATBLOCKFN *)nandfsformatblock; + nandfs->ll.reformatblock = (LOGFSREFORMATBLOCKFN *)nandfsreformatblock; + nandfs->ll.markblockbad = (LOGFSMARKBLOCKBADFN *)nandfsmarkblockbad; + nandfs->ll.getbaseblock = (LOGFSGETBASEBLOCKFN *)nandfsgetbaseblock; + nandfs->ll.getblocksize = (LOGFSGETBLOCKSIZEFN *)nandfsgetblocksize; + nandfs->ll.calcrawaddress = (LOGFSCALCRAWADDRESSFN *)nandfscalcrawaddress; + nandfs->ll.getblockstatus = (LOGFSGETBLOCKSTATUSFN *)nandfsgetblockstatus; + nandfs->ll.calcformat = (LOGFSCALCFORMATFN *)nandfscalcformat; + nandfs->ll.getopenstatus = (LOGFSGETOPENSTATUSFN *)nandfsgetopenstatus; + nandfs->ll.free = (LOGFSFREEFN *)nandfsfree; + nandfs->ll.sync = (LOGFSSYNCFN *)nandfssync; + *llp = (LogfsLowLevel *)nandfs; + return nil; +} + +void +nandfsfree(Nandfs *nandfs) +{ + if (nandfs) { + nandfsfreemem(nandfs->blockdata); + nandfsfreemem(nandfs); + } +} + +void +nandfssetmagic(Nandfs *nandfs, void *magic) +{ + nandfs->magic = magic; +} + +char * +nandfssync(Nandfs *nandfs) +{ + return (*nandfs->sync)(nandfs->magic); +} diff --git a/libnandfs/local.h b/libnandfs/local.h new file mode 100644 index 00000000..d5b4eecb --- /dev/null +++ b/libnandfs/local.h @@ -0,0 +1,51 @@ +typedef struct NandfsBlockData { + ulong path; + short tag; + ulong nerase; + int partial; +} NandfsBlockData; + +struct Nandfs { + LogfsLowLevel ll; + char *(*read)(void *magic, void *buf, long nbytes, ulong offset); + char *(*write)(void *magic, void *buf, long nbytes, ulong offset); + char *(*erase)(void *magic, long blockaddr); + char *(*sync)(void *magic); + void *magic; + long rawblocksize; + long baseblock; + long limitblock; + NandfsBlockData *blockdata; + int trace; + int worseblocks; + int printbad; +}; + +typedef struct NandfsAuxiliary { + uchar parth[4]; // ggpppppp pppppppp pppppppp pp1hhhhh (bigendian) self-protected + uchar tag; // self-protecting + uchar blockstatus; // self-protecting + uchar nerasemagicmsw[2]; // see nerasemagiclsw + uchar ecc2[3]; // self-protecting + uchar nerasemagiclsw[2]; // mmmmmm mmeeeeee eeeeeeeeee ee1hhhhh (bigendian) self-protected + uchar ecc1[3]; // self-protecting +} NandfsAuxiliary; + +#define getbig2(p) (((p)[0] << 8) | (p)[1]) +#define getbig4(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3]) +#define getlittle3(p) (((p)[2] << 16) | ((p)[1] << 8) | (p)[0]) +#define putlittle3(p, q) ((p)[0] = (q), (p)[1] = (q) >> 8, (p)[2] = (q) >> 16) +#define putbig2(p, q) ((p)[0] = (q) >> 8, (p)[1] = (q)) +#define putbig4(p, q) ((p)[0] = (q) >> 24, (p)[1] = (q) >> 16, (p)[2] = (q) >> 8, (p)[3] = (q)) + +LogfsLowLevelReadResult _nandfscorrectauxiliary(NandfsAuxiliary *hdr); + +extern uchar _nandfsvalidtags[]; +extern int _nandfsvalidtagscount; + +ulong _nandfshamming31_26calc(ulong in); +int _nandfshamming31_26correct(ulong *in); + +void _nandfsextracttags(NandfsAuxiliary *hdr, NandfsTags *tags); + +extern char Enomem[], Eperm[], Eio[]; diff --git a/libnandfs/markblockbad.c b/libnandfs/markblockbad.c new file mode 100644 index 00000000..6414c8d2 --- /dev/null +++ b/libnandfs/markblockbad.c @@ -0,0 +1,42 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +char * +nandfsmarkabsblockbad(Nandfs *nandfs, long absblock) +{ + NandfsAuxiliary hdr; + int page; + int ppb; + + memset(&hdr, 0xff, sizeof(hdr)); + hdr.blockstatus = 0xf0; // late failure + + ppb = 1 << nandfs->ll.l2pagesperblock; + for (page = 0; page < ppb; page++) { + char *errmsg = (*nandfs->write)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * absblock + page * NandfsFullSize + NandfsPageSize); + if (errmsg && strcmp(errmsg, Eio) != 0) + return errmsg; + } + + return nil; +} + +char * +nandfsmarkblockbad(Nandfs *nandfs, long block) +{ + char *errmsg; + errmsg = nandfsmarkabsblockbad(nandfs, block + nandfs->baseblock); + if (errmsg) + return errmsg; + + if (nandfs->blockdata) { + NandfsBlockData *d; + d = &nandfs->blockdata[block]; + d->tag = LogfsTbad; + } + + return nil; +} + diff --git a/libnandfs/mkfile b/libnandfs/mkfile new file mode 100644 index 00000000..72bdde29 --- /dev/null +++ b/libnandfs/mkfile @@ -0,0 +1,33 @@ +<../mkconfig + +LIB=libnandfs.a + +OFILES= \ + calcformat.$O\ + correctauxilliary.$O\ + ecc.$O\ + eraseblock.$O\ + extracttags.$O\ + findfreeblock.$O\ + formatblock.$O\ + getblockstatus.$O\ + hamming31_26.$O\ + init.$O\ + markblockbad.$O\ + open.$O\ + readblock.$O\ + readpage.$O\ + readpageauxilliary.$O\ + reformatblock.$O\ + setget.$O\ + updatepage.$O\ + writeblock.$O\ + writepageauxilliary.$O\ + +HFILES=\ + $ROOT/include/nandfs.h \ + $ROOT/include/logfs.h \ + local.h + +<$ROOT/mkfiles/mksyslib-$SHELLTYPE + diff --git a/libnandfs/open.c b/libnandfs/open.c new file mode 100644 index 00000000..12b49849 --- /dev/null +++ b/libnandfs/open.c @@ -0,0 +1,253 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +char * +nandfsopen(Nandfs *nandfs, long base, long limit, int trace, int xcount, long *xdata) +{ + NandfsBlockData *blockdata = nil; + long u; + ulong badones, goodones; + char *errmsg; + long possiblebaseblock, possiblesize; + long baseblock, limitblock; + int ppb; + + if (trace > 1) + print("nandfsopen: base %ld limit %ld ppb %d\n", base, limit, 1 << nandfs->ll.l2pagesperblock); + + if (nandfs->blockdata) + return Eperm; + + if (base % nandfs->rawblocksize) + return Ebadarg; + baseblock = base / nandfs->rawblocksize; + + if (limit == 0) + limitblock = nandfs->limitblock; + else if (limit % nandfs->rawblocksize) + return Ebadarg; + else + limitblock = limit / nandfs->rawblocksize; + + if (trace > 1) + print("nandfsopen: baseblock %ld limitblock %ld\n", baseblock, limitblock); + + possiblebaseblock = 0; + possiblesize = 0; + + /* + * search for Tboot block which will reveal the parameters + */ + nandfs->baseblock = 0; + + for (u = baseblock; u < limitblock; u++) { + NandfsTags tags; + LogfsLowLevelReadResult e; + int p; + int lim; + + lim = xcount + 3; + + for (p = 0; p < lim; p++) { + errmsg = nandfsreadpageauxiliary(nandfs, &tags, u, p, 1, &e); + if (errmsg) + goto error; + if (e != LogfsLowLevelReadResultOk || tags.magic != LogfsMagic || tags.tag != LogfsTboot) + break; + if (trace > 1) + print("block %lud/%d: 0x%.lux\n", u, p, tags.path); + switch (p) { + case 1: + possiblebaseblock = tags.path; + break; + case 2: + possiblesize = tags.path; + break; + default: + xdata[p - 3] = tags.path; + break; + } + } + if (p == lim) + break; + } + + if (u >= limitblock) { + errmsg = "no valid boot blocks found"; + goto error; + } + + if (possiblebaseblock < baseblock + || possiblebaseblock >= limitblock + || possiblebaseblock + possiblesize > limitblock + || possiblesize == 0) { + errmsg = "embedded parameters out of range"; + goto error; + } + + baseblock = possiblebaseblock; + limitblock = possiblebaseblock + possiblesize; + + if (trace > 0) { + int x; + print("nandfs filesystem detected: base %lud limit %lud", + baseblock, limitblock); + for (x = 0; x < xcount; x++) + print(" data%d %ld", x, xdata[x]); + print("\n"); + } + + blockdata = nandfsrealloc(nil, (limitblock - baseblock) * sizeof(NandfsBlockData)); + if (blockdata == nil) { + errmsg = Enomem; + goto error; + } + /* + * sanity check + * check the partition until 10 good blocks have been found + * check that bad blocks represent 10% or less + */ + + badones = goodones = 0; + ppb = 1 << nandfs->ll.l2pagesperblock; + for (u = baseblock; u < limitblock; u++) { + LogfsLowLevelReadResult firste, laste; + NandfsTags firsttags, lasttags; + errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste); + if (errmsg) + goto error; + errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste); + if (errmsg) + goto error; + if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) + continue; + if (firste == LogfsLowLevelReadResultOk && laste == LogfsLowLevelReadResultOk && firsttags.magic == LogfsMagic && + lasttags.magic == LogfsMagic) + goodones++; + else + badones++; + if (badones == 0 && goodones >= 10) + break; + } + + if (badones * 10 > goodones) { + errmsg = "most likely not a Log Filesystem"; + goto error; + } + + for (u = baseblock; u < limitblock; u++) { + int erased, partial; + LogfsLowLevelReadResult firste, laste; + NandfsTags firsttags, lasttags, newtags; + int markedbad; + errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste); + if (errmsg) + goto error; + errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste); + if (errmsg) + goto error; + if (trace > 1) + print("%lud: ", u); + if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) { + if (trace > 1) + print("bad\n"); + blockdata[u - baseblock].tag = LogfsTbad; + continue; + } + newtags = firsttags; + erased = 0; + partial = 0; + if (firsttags.tag != lasttags.tag) { + partial = 1; + if (trace > 1) + print("partially written\n"); + /* + * partially written block + * if Tboot, then it is either + * a failure during logfsformat() - well, we never got started, so give up + * a failure during blocktransfer() - erase it as the transfer was not completed + * tell the difference by the presence of another block with the same path + * if Tnone, then it's a no brainer + * if anything else, leave alone + */ + if (newtags.tag == LogfsTnone) { + newtags.tag = LogfsTnone; + newtags.path = NandfsPathMask; + errmsg = nandfseraseblock(nandfs, u, nil, &markedbad); + if (errmsg) + goto error; + if (markedbad) { + blockdata[u - baseblock].tag = LogfsTbad; + continue; + } + /* now erased */ + erased = 1; + partial = 0; + } + } + if (!erased && !partial && firste == LogfsLowLevelReadResultAllOnes) { + if (trace > 1) + print("probably erased"); + /* + * finding erased blocks at this stage is a rare event, so + * erase again just in case + */ + newtags.tag = LogfsTnone; + newtags.path = NandfsPathMask; + newtags.nerase = 1; // what do I do here? + errmsg = nandfseraseblock(nandfs, u, nil, &markedbad); + if (errmsg) + goto error; + if (markedbad) { + blockdata[u - baseblock].tag = LogfsTbad; + continue; + } + erased = 1; + } + if (erased) { + newtags.magic = 'V'; + errmsg = nandfseraseblock(nandfs, u, nil, &markedbad); + if (errmsg) + goto error; + if (markedbad) { + blockdata[u - baseblock].tag = LogfsTbad; + continue; + } + } + switch (newtags.tag) { + case LogfsTboot: + case LogfsTnone: + case LogfsTdata: + case LogfsTlog: + blockdata[u - baseblock].path = newtags.path; + blockdata[u - baseblock].tag = newtags.tag; + blockdata[u - baseblock].nerase = newtags.nerase; + blockdata[u - baseblock].partial = partial; + if (trace > 1) + print("%s 0x%.8lux %lud\n", + logfstagname(blockdata[u - baseblock].tag), + blockdata[u - baseblock].path, + blockdata[u - baseblock].nerase); + continue; + } + break; + } + nandfs->ll.blocks = u - baseblock; + nandfs->baseblock = baseblock; + nandfs->blockdata = nandfsrealloc(nil, nandfs->ll.blocks * sizeof(NandfsBlockData)); + if (nandfs->blockdata == nil) { + errmsg = Enomem; + goto error; + } + nandfs->trace = trace; + memmove(nandfs->blockdata, blockdata, sizeof(*nandfs->blockdata) * nandfs->ll.blocks); + nandfsfreemem(blockdata); + if (trace > 0) + print("nandfsopen: success\n"); + return nil; +error: + nandfsfreemem(blockdata); + return errmsg; +} diff --git a/libnandfs/readblock.c b/libnandfs/readblock.c new file mode 100644 index 00000000..cbf3222b --- /dev/null +++ b/libnandfs/readblock.c @@ -0,0 +1,36 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +char * +nandfsreadblock(Nandfs *nandfs, void *buf, long block, LogfsLowLevelReadResult *blocke) +{ + int p; + uchar *bp; + int ppb; + + *blocke = LogfsLowLevelReadResultOk; + ppb = 1 << nandfs->ll.l2pagesperblock; + for (p = 0, bp = buf; p < ppb; p++, bp += NandfsPageSize) { + LogfsLowLevelReadResult e; + char *errmsg; + errmsg = nandfsreadpage(nandfs, bp, nil, block, p, nandfs->printbad, &e); + if (errmsg) + return errmsg; + switch (e) { + case LogfsLowLevelReadResultOk: + break; + case LogfsLowLevelReadResultSoftError: + if (*blocke == LogfsLowLevelReadResultOk) + *blocke = LogfsLowLevelReadResultSoftError; + break; + case LogfsLowLevelReadResultHardError: + if (*blocke == LogfsLowLevelReadResultOk || *blocke == LogfsLowLevelReadResultSoftError) + *blocke = LogfsLowLevelReadResultHardError; + break; + } + } + + return nil; +} diff --git a/libnandfs/readpage.c b/libnandfs/readpage.c new file mode 100644 index 00000000..9ae3ed43 --- /dev/null +++ b/libnandfs/readpage.c @@ -0,0 +1,52 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "nandecc.h" +#include "local.h" + +char * +nandfsreadpage(Nandfs *nandfs, void *buf, NandfsTags *tags, long block, int page, int reportbad, LogfsLowLevelReadResult *result) +{ + ulong ecc1, ecc2, storedecc1, storedecc2; + NandEccError e1, e2; + ulong rawoffset; + NandfsAuxiliary hdr; + char *errmsg; + + rawoffset = nandfs->rawblocksize * (nandfs->baseblock + block) + NandfsFullSize * page; + errmsg = (*nandfs->read)(nandfs->magic, buf, NandfsPageSize, rawoffset); + if (errmsg) + return errmsg; + errmsg = (*nandfs->read)(nandfs->magic, &hdr, sizeof(hdr), rawoffset + NandfsPageSize); + if (errmsg) + return errmsg; + ecc1 = nandecc(buf); + ecc2 = nandecc((uchar *)buf + 256); + storedecc1 = getlittle3(hdr.ecc1); + storedecc2 = getlittle3(hdr.ecc2); + e1 = nandecccorrect(buf, ecc1, &storedecc1, reportbad); + e2 = nandecccorrect((uchar *)buf + 256, ecc2, &storedecc2, reportbad); + if (e1 == NandEccErrorBad || e2 == NandEccErrorBad) + *result = LogfsLowLevelReadResultHardError; + else if (e1 != NandEccErrorGood || e2 != NandEccErrorGood) + *result = LogfsLowLevelReadResultSoftError; + else + *result = LogfsLowLevelReadResultOk; + if (tags) { + *result = _nandfscorrectauxiliary(&hdr); + _nandfsextracttags(&hdr, tags); + } + return nil; +} + +char * +nandfsreadpagerange(Nandfs *nandfs, void *buf, long block, int page, int offset, int count, LogfsLowLevelReadResult *result) +{ + char *errmsg; + uchar tmpbuf[NandfsPageSize]; + errmsg = nandfsreadpage(nandfs, tmpbuf, nil, block, page, 1, result); + if (errmsg == nil) + memcpy(buf, tmpbuf + offset, count); + return errmsg; +} + diff --git a/libnandfs/readpageauxilliary.c b/libnandfs/readpageauxilliary.c new file mode 100644 index 00000000..ba71d2b5 --- /dev/null +++ b/libnandfs/readpageauxilliary.c @@ -0,0 +1,35 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +static int +countzeros(uchar byte) +{ + int b, count; + for (b = 0x80, count = 0; b; b>>= 1) + if ((byte & b) == 0) + count++; + return count; +} + +char * +nandfsreadpageauxiliary(Nandfs *nandfs, NandfsTags *tags, long block, int page, int correct, LogfsLowLevelReadResult *result) +{ + NandfsAuxiliary hdr; + char *rv; + + rv = (*nandfs->read)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * (nandfs->baseblock + block) + page * NandfsFullSize + NandfsPageSize); + if (rv) + return rv; + if (countzeros(hdr.blockstatus) > 2) { + *result = LogfsLowLevelReadResultBad; + return nil; + } + if (correct) + *result = _nandfscorrectauxiliary(&hdr); + else + *result = LogfsLowLevelReadResultOk; + _nandfsextracttags(&hdr, tags); + return nil; +} diff --git a/libnandfs/reformatblock.c b/libnandfs/reformatblock.c new file mode 100644 index 00000000..c0d790bf --- /dev/null +++ b/libnandfs/reformatblock.c @@ -0,0 +1,34 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +char * +nandfsreformatblock(Nandfs *nandfs, long block, uchar tag, ulong path, int xcount, long *xdata, void *llsave, int *markedbad) +{ + int bad; + char *errmsg; + NandfsBlockData *d; + long nerase; + + if (nandfs->blockdata == nil) + return Eperm; + + nerase = *(ulong *)llsave; + + errmsg = nandfsformatblock(nandfs, block, tag, path, + nandfs->baseblock, nandfs->limitblock - nandfs->baseblock, xcount, xdata, &nerase, &bad); + + if (markedbad) + *markedbad = bad; + if (errmsg) + return errmsg; + + d = &nandfs->blockdata[block]; + d->tag = bad ? LogfsTbad : tag; + d->path = path; + d->nerase = nerase; + d->partial = 0; + + return nil; +} diff --git a/libnandfs/setget.c b/libnandfs/setget.c new file mode 100644 index 00000000..4a25f494 --- /dev/null +++ b/libnandfs/setget.c @@ -0,0 +1,101 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +short +nandfsgettag(Nandfs *nandfs, long block) +{ + if (nandfs->blockdata) + return nandfs->blockdata[block].tag; + return 0; +} + +void +nandfssettag(Nandfs *nandfs, long block, short tag) +{ + if (nandfs->blockdata) { + nandfs->blockdata[block].tag = tag; + if (tag == LogfsTworse) + nandfs->worseblocks = 1; + return; + } +} + +long +nandfsgetpath(Nandfs *nandfs, long block) +{ + if (nandfs->blockdata) + return nandfs->blockdata[block].path; + return 0; +} + +void +nandfssetpath(Nandfs *nandfs, long block, ulong path) +{ + if (nandfs->blockdata) { + nandfs->blockdata[block].path = path; + return; + } +} + +long +nandfsgetnerase(Nandfs *nandfs, long block) +{ + if (nandfs->blockdata) + return nandfs->blockdata[block].nerase; + return 0; +} + +void +nandfssetnerase(Nandfs *nandfs, long block, ulong nerase) +{ + if (nandfs->blockdata) { + nandfs->blockdata[block].nerase = nerase; + return; + } +} + +int +nandfsgetblockpartialformatstatus(Nandfs *nandfs, long block) +{ + if (nandfs->blockdata) + return nandfs->blockdata[block].partial; + return 0; +} + +void +nandfssetblockpartialformatstatus(Nandfs *nandfs, long block, int partial) +{ + if (nandfs->blockdata) { + nandfs->blockdata[block].partial = partial; + return; + } +} + +long +nandfsgetbaseblock(Nandfs *nandfs) +{ + return nandfs->baseblock; +} + +int +nandfsgetblocksize(Nandfs *nandfs) +{ + return 1 << (nandfs->ll.l2pagesperblock + NandfsL2PageSize); +} + +ulong +nandfscalcrawaddress(Nandfs *nandfs, long pblock, int dataoffset) +{ + int lpage, pageoffset; + lpage = dataoffset / NandfsPageSize; + pageoffset = dataoffset % NandfsPageSize; + return nandfs->rawblocksize * pblock + lpage * NandfsFullSize + pageoffset; +} + +int +nandfsgetopenstatus(Nandfs *nandfs) +{ + return nandfs->blockdata != nil; +} diff --git a/libnandfs/updatepage.c b/libnandfs/updatepage.c new file mode 100644 index 00000000..afe70b79 --- /dev/null +++ b/libnandfs/updatepage.c @@ -0,0 +1,38 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "nandecc.h" +#include "local.h" + +char * +nandfsupdatepage(Nandfs *nandfs, void *buf, ulong path, uchar tag, long block, int page) +{ + uchar tbuf[NandfsFullSize]; + ulong ecc1, ecc2; + ulong rawoffset; + NandfsAuxiliary *hdr; + + rawoffset = (nandfs->baseblock + block) * nandfs->rawblocksize + page * NandfsFullSize; + memmove(tbuf, buf, NandfsPageSize); + ecc1 = nandecc(tbuf); + ecc2 = nandecc(tbuf + 256); + hdr = (NandfsAuxiliary *)(tbuf + NandfsPageSize); + memset(hdr, 0xff, sizeof(*hdr)); + hdr->tag = tag; + if (path < NandfsPathMask) { + ulong tmp = _nandfshamming31_26calc(path << 6) | (1 << 5); + putbig4(hdr->parth, tmp); + } + putlittle3(hdr->ecc1, ecc1); + putlittle3(hdr->ecc2, ecc2); + return (*nandfs->write)(nandfs->magic, tbuf, sizeof(tbuf), rawoffset); +} + +char * +nandfswritepage(Nandfs *nandfs, void *buf, long block, int page) +{ + ulong writepath = nandfsgetpath(nandfs, block); + uchar writetag = nandfsgettag(nandfs, block); +//print("block %ld writepath 0x%.8lux writetag 0x%.2ux\n", block, writepath, writetag); + return nandfsupdatepage(nandfs, buf, writepath, writetag, block, page); +} diff --git a/libnandfs/writeblock.c b/libnandfs/writeblock.c new file mode 100644 index 00000000..0e4b9c3d --- /dev/null +++ b/libnandfs/writeblock.c @@ -0,0 +1,47 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +char * +nandfswriteblock(Nandfs *nandfs, void *buf, uchar tag, ulong path, int xcount, long *data, long block) +{ + int p; + char *errmsg; + + ulong opath = nandfsgetpath(nandfs, block); + ulong writepath = (~opath | path) & NandfsPathMask; + uchar writetag = ~nandfsgettag(nandfs, block) | tag; + int ppb = 1 << nandfs->ll.l2pagesperblock; + + for (p = 0; p < ppb; p++) { + ulong wp; + if (p > 0 && p <= 2 + xcount) { + switch (p) { + case 1: + wp = (~opath | nandfsgetbaseblock(nandfs)) & NandfsPathMask; + break; + case 2: + wp = (~opath | nandfs->ll.blocks) & NandfsPathMask; + break; + default: + wp = (~opath | data[p - 3]) & NandfsPathMask; + break; + } + } + else + wp = writepath; + errmsg = nandfsupdatepage(nandfs, buf, wp, writetag, block, p); + if (errmsg) + return errmsg; +#ifdef LOGFSTEST + if (logfstest.partialupdate && p > 0) { + print("skipping pageupdate\n"); + break; + } +#endif + buf = (uchar *)buf + NandfsPageSize; + } + + return nil; +} diff --git a/libnandfs/writepageauxilliary.c b/libnandfs/writepageauxilliary.c new file mode 100644 index 00000000..6d2d6b87 --- /dev/null +++ b/libnandfs/writepageauxilliary.c @@ -0,0 +1,33 @@ +#include "lib9.h" +#include "logfs.h" +#include "nandfs.h" +#include "local.h" + +/* + * update the tags in a page's auxiliary area + * only touch the fields if they contain some zeros, and compute the hamming codes + * as well + */ + +char * +nandfswritepageauxiliary(Nandfs *nandfs, NandfsTags *tags, long absblock, int page) +{ + NandfsAuxiliary hdr; + ulong tmp; + ushort htmp; + + memset(&hdr, 0xff, sizeof(hdr)); + if (tags->path < NandfsPathMask) { + tmp = _nandfshamming31_26calc((tags->path << 6)) | (1 << 5); + putbig4(hdr.parth, tmp); + } + if (tags->nerase < NandfsNeraseMask || tags->magic != 0xff) { + tmp = _nandfshamming31_26calc((tags->magic << 24) | (tags->nerase << 6)) | (1 << 5); + htmp = tmp >> 16; + putbig2(hdr.nerasemagicmsw, htmp); + putbig2(hdr.nerasemagiclsw, tmp); + } + if (tags->tag != 0xff) + hdr.tag = tags->tag; + return (*nandfs->write)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * absblock + page * NandfsFullSize + NandfsPageSize); +} |
