1*28942eadSforsyth #include "logfsos.h"
237da2899SCharles.Forsyth #include "logfs.h"
337da2899SCharles.Forsyth #include "nandfs.h"
437da2899SCharles.Forsyth #include "local.h"
537da2899SCharles.Forsyth
637da2899SCharles.Forsyth static int
hammingdistance(uchar a,uchar b)737da2899SCharles.Forsyth hammingdistance(uchar a, uchar b)
837da2899SCharles.Forsyth {
937da2899SCharles.Forsyth uchar c;
1037da2899SCharles.Forsyth int i, k;
1137da2899SCharles.Forsyth if (a == b)
1237da2899SCharles.Forsyth return 0;
1337da2899SCharles.Forsyth c = a ^ b;
1437da2899SCharles.Forsyth for (i = 0x80, k = 0; i; i >>= 1)
1537da2899SCharles.Forsyth if (c & i)
1637da2899SCharles.Forsyth k++;
1737da2899SCharles.Forsyth return k;
1837da2899SCharles.Forsyth }
1937da2899SCharles.Forsyth
2037da2899SCharles.Forsyth static int
allones(uchar * data,int len)2137da2899SCharles.Forsyth allones(uchar *data, int len)
2237da2899SCharles.Forsyth {
2337da2899SCharles.Forsyth while (len-- > 0)
2437da2899SCharles.Forsyth if (*data++ != 0xff)
2537da2899SCharles.Forsyth return 0;
2637da2899SCharles.Forsyth return 1;
2737da2899SCharles.Forsyth }
2837da2899SCharles.Forsyth
2937da2899SCharles.Forsyth LogfsLowLevelReadResult
_nandfscorrectauxiliary(NandfsAuxiliary * hdr)3037da2899SCharles.Forsyth _nandfscorrectauxiliary(NandfsAuxiliary *hdr)
3137da2899SCharles.Forsyth {
3237da2899SCharles.Forsyth /*
3337da2899SCharles.Forsyth * correct single bit errors, detect more than 1, in
3437da2899SCharles.Forsyth * tag, signature
3537da2899SCharles.Forsyth * TODO: add nerase and path protection
3637da2899SCharles.Forsyth */
3737da2899SCharles.Forsyth LogfsLowLevelReadResult e;
3837da2899SCharles.Forsyth int x;
3937da2899SCharles.Forsyth int min, minx;
4037da2899SCharles.Forsyth
4137da2899SCharles.Forsyth e = LogfsLowLevelReadResultOk;
4237da2899SCharles.Forsyth
4337da2899SCharles.Forsyth min = 8;
4437da2899SCharles.Forsyth minx = 0;
4537da2899SCharles.Forsyth for (x = 0; x < _nandfsvalidtagscount; x++) {
4637da2899SCharles.Forsyth int d = hammingdistance(hdr->tag, _nandfsvalidtags[x]);
4737da2899SCharles.Forsyth if (d < min) {
4837da2899SCharles.Forsyth min = d;
4937da2899SCharles.Forsyth minx = x;
5037da2899SCharles.Forsyth if (d == 0)
5137da2899SCharles.Forsyth break;
5237da2899SCharles.Forsyth }
5337da2899SCharles.Forsyth }
5437da2899SCharles.Forsyth if (min == 1) {
5537da2899SCharles.Forsyth hdr->tag = _nandfsvalidtags[minx];
5637da2899SCharles.Forsyth e = LogfsLowLevelReadResultSoftError;
5737da2899SCharles.Forsyth }
5837da2899SCharles.Forsyth else if (min > 1)
5937da2899SCharles.Forsyth e = LogfsLowLevelReadResultHardError;
6037da2899SCharles.Forsyth else {
6137da2899SCharles.Forsyth if (hdr->tag != LogfsTnone) {
6237da2899SCharles.Forsyth ulong tmp = getbig4(hdr->parth);
63*28942eadSforsyth if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) {
6437da2899SCharles.Forsyth putbig4(hdr->parth, tmp);
6537da2899SCharles.Forsyth if (e != LogfsLowLevelReadResultOk)
6637da2899SCharles.Forsyth e = LogfsLowLevelReadResultSoftError;
6737da2899SCharles.Forsyth }
6837da2899SCharles.Forsyth tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw);
6937da2899SCharles.Forsyth if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) {
7037da2899SCharles.Forsyth putbig2(hdr->nerasemagicmsw, tmp >> 16);
7137da2899SCharles.Forsyth putbig2(hdr->nerasemagiclsw, tmp);
7237da2899SCharles.Forsyth if (e != LogfsLowLevelReadResultOk)
7337da2899SCharles.Forsyth e = LogfsLowLevelReadResultSoftError;
7437da2899SCharles.Forsyth }
7537da2899SCharles.Forsyth }
7637da2899SCharles.Forsyth else if (allones((uchar *)hdr, sizeof(*hdr)))
7737da2899SCharles.Forsyth e = LogfsLowLevelReadResultAllOnes;
7837da2899SCharles.Forsyth }
7937da2899SCharles.Forsyth
8037da2899SCharles.Forsyth return e;
8137da2899SCharles.Forsyth }
82