xref: /inferno-os/libnandfs/ecc.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include "logfsos.h"
2 #include "nandecc.h"
3 
4 static uchar ecctab[] = {
5 	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
6 	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
7 	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
8 	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
9 	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
10 	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
11 	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
12 	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
13 	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
14 	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
15 	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
16 	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
17 	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
18 	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
19 	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
20 	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
21 };
22 
23 ulong
24 nandecc(uchar *buf)
25 {
26 	int cp, zeros, ones, im;
27 	int lp, om;
28 	int i;
29 
30 	cp = 0xff;
31 	zeros = 0xff;
32 	ones = 0xff;
33 	for (i = 0; i < 256; i++) {
34 		int tabent = ecctab[buf[i]];
35 		cp ^= tabent;
36 		if (tabent & 1) {
37 			zeros ^= ~i;
38 			ones ^= i;
39 		}
40 	}
41 	lp = 0;
42 	for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) {
43 		if (ones & im)
44 			lp |= om;
45 		om >>= 1;
46 		if (zeros & im)
47 			lp |= om;
48 	}
49 	return (((cp & 0xff) | 3) << 16) | lp;
50 }
51 
52 #define CORRECTABLEMASK 0x545555
53 
54 NandEccError
55 nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad)
56 {
57 	ulong xorecc;
58 	ulong mask;
59 	int k;
60 
61 	if (calcecc == *storedecc)
62 		return NandEccErrorGood;
63 	if (reportbad)
64 		print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n", calcecc, *storedecc);
65 	xorecc = calcecc ^ *storedecc;
66 	if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) {
67 		ulong imask;
68 		ushort out;
69 		ushort omask;
70 		int line, col;
71 
72 		for (imask = 0x800000, omask = 0x800, out = 0; imask; imask >>= 2, omask >>= 1) {
73 			if (xorecc & imask)
74 				out |= omask;
75 		}
76 		line = out & 0xff;
77 		col = out >> 9;
78 		if (reportbad)
79 			print("nandecccorrect: single bit error line %d col %d\n", line, col);
80 		buf[line] ^= (1 << col);
81 		*storedecc = calcecc;
82 		return NandEccErrorOneBit;
83 	}
84 	for (mask = 0x800000, k = 0; mask; mask >>= 1)
85 		if (mask & xorecc)
86 			k++;
87 	if (k == 1) {
88 		if (reportbad)
89 			print("nandecccorrect: single bit error in ecc\n");
90 		// assume the stored ecc was wrong
91 		*storedecc = calcecc;
92 		return NandEccErrorOneBitInEcc;
93 	}
94 	if (reportbad)
95 		print("nandecccorrect: 2 bit error\n");
96 	return NandEccErrorBad;
97 }
98 
99