xref: /inferno-os/libnandfs/correctauxilliary.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 #include "lib9.h"
2 #include "logfs.h"
3 #include "nandfs.h"
4 #include "local.h"
5 
6 static int
7 hammingdistance(uchar a, uchar b)
8 {
9 	uchar c;
10 	int i, k;
11 	if (a == b)
12 		return 0;
13 	c =  a ^ b;
14 	for (i = 0x80, k = 0; i; i >>= 1)
15 		if (c & i)
16 			k++;
17 	return k;
18 }
19 
20 static int
21 allones(uchar *data, int len)
22 {
23 	while (len-- > 0)
24 		if (*data++ != 0xff)
25 			return 0;
26 	return 1;
27 }
28 
29 LogfsLowLevelReadResult
30 _nandfscorrectauxiliary(NandfsAuxiliary *hdr)
31 {
32 	/*
33 	 * correct single bit errors, detect more than 1, in
34 	 * tag, signature
35 	 * TODO: add nerase and path protection
36 	 */
37 	LogfsLowLevelReadResult e;
38 	int x;
39 	int min, minx;
40 
41 	e = LogfsLowLevelReadResultOk;
42 
43 	min = 8;
44 	minx = 0;
45 	for (x = 0; x < _nandfsvalidtagscount; x++) {
46 		int d = hammingdistance(hdr->tag, _nandfsvalidtags[x]);
47 		if (d < min) {
48 			min = d;
49 			minx = x;
50 			if (d == 0)
51 				break;
52 		}
53 	}
54 	if (min == 1) {
55 		hdr->tag = _nandfsvalidtags[minx];
56 		e = LogfsLowLevelReadResultSoftError;
57 	}
58 	else if (min > 1)
59 		e = LogfsLowLevelReadResultHardError;
60 	else {
61 		if (hdr->tag != LogfsTnone) {
62 			ulong tmp = getbig4(hdr->parth);
63 			if (tmp != 0xfffffffff && _nandfshamming31_26correct(&tmp)) {
64 				putbig4(hdr->parth, tmp);
65 				if (e != LogfsLowLevelReadResultOk)
66 					e = LogfsLowLevelReadResultSoftError;
67 			}
68 			tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw);
69 			if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) {
70 				putbig2(hdr->nerasemagicmsw, tmp >> 16);
71 				putbig2(hdr->nerasemagiclsw, tmp);
72 				if (e != LogfsLowLevelReadResultOk)
73 					e = LogfsLowLevelReadResultSoftError;
74 			}
75 		}
76 		else if (allones((uchar *)hdr, sizeof(*hdr)))
77 			e = LogfsLowLevelReadResultAllOnes;
78 	}
79 
80 	return e;
81 }
82