xref: /inferno-os/libnandfs/correctauxilliary.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
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