windows-nt/Source/XPSP1/NT/drivers/storage/tffsport/reedsol.c
2020-09-26 16:20:57 +08:00

553 lines
14 KiB
C

/* HOOK. Fixed comments; otherwise impossible to compile */
/*
* $Log: V:/Flite/archives/TrueFFS5/Src/REEDSOL.C_V $
*
* Rev 1.3 Jul 13 2001 01:10:00 oris
* Moved saved syndrome array definition (used by d2tst).
*
* Rev 1.2 Apr 09 2001 15:10:20 oris
* End with an empty line.
*
* Rev 1.1 Apr 01 2001 08:00:14 oris
* copywrite notice.
*
* Rev 1.0 Feb 04 2001 12:37:38 oris
* Initial revision.
*
*/
/************************************************************************/
/* */
/* FAT-FTL Lite Software Development Kit */
/* Copyright (C) M-Systems Ltd. 1995-2001 */
/* */
/************************************************************************/
#include "reedsol.h"
#define T 2 /* Number of recoverable errors */
#define SYND_LEN (T*2) /* length of syndrom vector */
#define K512 (((512+1)*8+6)/10) /* number of inf symbols for record
of 512 bytes (K512=411) */
#define N512 (K512 + SYND_LEN) /* code word length for record of 512 bytes */
#define INIT_DEG 510
#define MOD 1023
#define BLOCK_SIZE 512
#ifdef D2TST
byte saveSyndromForDumping[SYNDROM_BYTES];
#endif /* D2TST */
static short gfi(short val);
static short gfmul( short f, short s );
static short gfdiv( short f, short s );
static short flog(short val);
static short alog(short val);
/*------------------------------------------------------------------------------*/
/* Function Name: RTLeightToTen */
/* Purpose......: convert an array of five 8-bit values into an array of */
/* four 10-bit values, from right to left. */
/* Returns......: Nothing */
/*------------------------------------------------------------------------------*/
static void RTLeightToTen(char *reg8, unsigned short reg10[])
{
reg10[0] = (reg8[0] & 0xFF) | ((reg8[1] & 0x03) << 8);
reg10[1] = ((reg8[1] & 0xFC) >> 2) | ((reg8[2] & 0x0F) << 6);
reg10[2] = ((reg8[2] & 0xF0) >> 4) | ((reg8[3] & 0x3F) << 4);
reg10[3] = ((reg8[3] & 0xC0) >> 6) | ((reg8[4] & 0xFF) << 2);
}
/*----------------------------------------------------------------------------*/
static void unpack( short word, short length, short vector[] )
/* */
/* Function unpacks word into vector */
/* */
/* Parameters: */
/* word - word to be unpacked */
/* vector - array to be filled */
/* length - number of bits in word */
{
short i, *ptr;
ptr = vector + length - 1;
for( i = 0; i < length; i++ )
{
*ptr-- = word & 1;
word >>= 1;
}
}
/*----------------------------------------------------------------------------*/
static short pack( short *vector, short length )
/* */
/* Function packs vector into word */
/* */
/* Parameters: */
/* vector - array to be packed */
/* length - number of bits in word */
{
short tmp, i;
vector += length - 1;
tmp = 0;
i = 1;
while( length-- > 0 )
{
if( *vector-- )
tmp |= i;
i <<= 1;
}
return( tmp );
}
/*----------------------------------------------------------------------------*/
static short gfi( short val) /* GF inverse */
{
return alog((short)(MOD-flog(val)));
}
/*----------------------------------------------------------------------------*/
static short gfmul( short f, short s ) /* GF multiplication */
{
short i;
if( f==0 || s==0 )
return 0;
else
{
i = flog(f) + flog(s);
if( i > MOD ) i -= MOD;
return( alog(i) );
}
}
/*----------------------------------------------------------------------------*/
static short gfdiv( short f, short s ) /* GF division */
{
return gfmul(f,gfi(s));
}
/*----------------------------------------------------------------------------*/
static void residue_to_syndrom( short reg[], short realsynd[] )
{
short i,l,alpha,x,s,x4;
short deg,deg4;
for(i=0,deg=INIT_DEG;i<SYND_LEN;i++,deg++)
{
s = reg[0];
alpha = x = alog(deg);
deg4 = deg+deg;
if( deg4 >= MOD ) deg4 -= MOD;
deg4 += deg4;
if( deg4 >= MOD ) deg4 -= MOD;
x4 = alog(deg4);
for(l=1;l<SYND_LEN;l++)
{
s ^= gfmul( reg[l], x );
x = gfmul( alpha, x );
}
realsynd[i] = gfdiv( s, x4 );
}
}
/*----------------------------------------------------------------------------*/
static short alog(short i)
{
short j=0, val=1;
for( ; j < i ; j++ )
{
val <<= 1 ;
if ( val > 0x3FF )
{
if ( val & 8 ) val -= (0x400+7);
else val -= (0x400-9);
}
}
return val ;
}
static short flog(short val)
{
short j, val1;
if (val == 0)
return (short)0xFFFF;
j=0;
val1=1;
for( ; j <= MOD ; j++ )
{
if (val1 == val)
return j;
val1 <<= 1 ;
if ( val1 > 0x3FF )
{
if ( val1 & 8 ) val1 -= (0x400+7);
else val1 -= (0x400-9);
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
static short convert_to_byte_patterns( short *locators, short *values,
short noferr, short *blocs, short *bvals )
{
static short mask[] = { 0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
short i,j,n, n0, n1, tmp;
short n_bit, n_byte, k_bit, nb;
for( i = 0, nb = 0; i< noferr; i++)
{
n = locators[i];
tmp = values[i];
n_bit = n *10 - 6 ;
n_byte = n_bit >> 3;
k_bit = n_bit - (n_byte<<3);
n_byte++;
if( k_bit == 7 )
{
/* 3 corrupted bytes */
blocs[nb] = n_byte+1;
bvals[nb++] = tmp & 1 ? 0x80 : 0;
tmp >>= 1;
blocs[nb] = n_byte;
bvals[nb++] = tmp & 0xff;
tmp >>= 8;
bvals[nb++] = tmp & 0xff;
}
else
{
n0 = 8 - k_bit;
n1 = 10 - n0;
blocs[nb] = n_byte;
bvals[nb++] = (tmp & mask[n1]) << (8 - n1);
tmp >>= n1;
blocs[nb] = n_byte - 1;
bvals[nb++] = (tmp & mask[n0]);
}
}
for( i = 0, j = -1; i < nb; i++ )
{
if( bvals[i] == 0 ) continue;
if( (blocs[i] == blocs[j]) && ( j>= 0 ) )
{
bvals[j] |= bvals[i];
}
else
{
j++;
blocs[j] = blocs[i];
bvals[j] = bvals[i];
}
}
return j+1;
}
/*----------------------------------------------------------------------------*/
static short deg512( short x )
{
short i;
short l,m;
l = flog(x);
for( i=0;i<9;i++)
{
m = 0;
if( (l & 0x200) )
m = 1;
l = ( ( l << 1 ) & 0x3FF ) | m;
}
return alog(l);
}
/*----------------------------------------------------------------------------*/
static short decoder_for_2_errors( short s[], short lerr[], short verr[] )
{
/* decoder for correcting up to 2 errors */
short i,j,k,temp,delta;
short ind, x1, x2;
short r1, r2, r3, j1, j2;
short sigma1, sigma2;
short xu[10], ku[10];
short yd, yn;
ind = 0;
for(i=0;i<SYND_LEN;i++)
if( s[i] != 0 )
ind++; /* ind = number of nonzero syndrom symbols */
if( ind == 0 ) return 0; /* no errors */
if( ind < 4 )
goto two_or_more_errors;
/* checking s1/s0 = s2/s1 = s3/s2 = alpha**j for some j */
r1 = gfdiv( s[1], s[0] );
r2 = gfdiv( s[2], s[1] );
r3 = gfdiv( s[3], s[2] );
if( r1 != r2 || r2 != r3)
goto two_or_more_errors;
j = flog(r1);
if( j > 414 )
goto two_or_more_errors;
lerr[0] = j;
/* pattern = (s0/s1)**(510+1) * s1
or
pattern = (s0/s1)**(512 - 1 ) * s1 */
temp = gfi( r1 );
#ifndef NT5PORT
{
int i;
for (i = 0; i < 9; i++)
temp = gfmul( temp, temp ); /* deg = 512 */
}
#else /*NT5PORT*/
for (i = 0; i < 9; i++)
{
temp = gfmul( temp, temp ); /* deg = 512 */
}
#endif /*NT5PORT*/
verr[0] = gfmul( gfmul(temp, r1), s[1] );
return 1; /* 1 error */
two_or_more_errors:
delta = gfmul( s[0], s[2] ) ^ gfmul( s[1], s[1] );
if( delta == 0 )
return -1; /* uncorrectable error */
temp = gfmul( s[1], s[3] ) ^ gfmul( s[2], s[2] );
if( temp == 0 )
return -1; /* uncorrectable error */
sigma2 = gfdiv( temp, delta );
temp = gfmul( s[1], s[2] ) ^ gfmul( s[0], s[3] );
if( temp == 0 )
return -1; /* uncorrectable error */
sigma1 = gfdiv( temp, delta );
k = gfdiv( sigma2, gfmul( sigma1, sigma1 ) );
unpack( k, 10, ku );
if( ku[2] != 0 )
return -1;
xu[4] = ku[9];
xu[5] = ku[0] ^ ku[1];
xu[6] = ku[6] ^ ku[9];
xu[3] = ku[4] ^ ku[9];
xu[1] = ku[3] ^ ku[4] ^ ku[6];
xu[0] = ku[0] ^ xu[1];
xu[8] = ku[8] ^ xu[0];
xu[7] = ku[7] ^ xu[3] ^ xu[8];
xu[2] = ku[5] ^ xu[7] ^ xu[5] ^ xu[0];
xu[9] = 0;
x1 = pack( xu, 10 );
x2 = x1 | 1;
x1 = gfmul( sigma1, x1 );
x2 = gfmul( sigma1, x2 );
j1 = flog(x1);
j2 = flog(x2);
if( (j1 > 414) || (j2 > 414) )
return -1;
r1 = x1 ^ x2;
r2 = deg512( x1 );
temp = gfmul( x1, x1 );
r2 = gfdiv( r2, temp );
yd = gfmul( r2, r1 );
if( yd == 0 )
return -1;
yn = gfmul( s[0], x2 ) ^ s[1];
if( yn == 0 )
return -1;
verr[0] = gfdiv( yn, yd );
r2 = deg512( x2 );
temp = gfmul( x2, x2 );
r2 = gfdiv( r2, temp );
yd = gfmul( r2, r1 );
if( yd == 0 )
return -1;
yn = gfmul( s[0], x1 ) ^ s[1];
if( yn == 0 )
return -1;
verr[1] = gfdiv( yn, yd );
if( j1 > j2 ) {
lerr[0] = j2;
lerr[1] = j1;
temp = verr[0];
verr[0] = verr[1];
verr[1] = temp;
}
else
{
lerr[0] = j1;
lerr[1] = j2;
}
return 2;
}
/*------------------------------------------------------------------------------*/
/* Function Name: flDecodeEDC */
/* Purpose......: Trys to correct errors. */
/* errorSyndrom[] should contain the syndrom as 5 bytes and one */
/* parity byte. (identical to the output of calcEDCSyndrom()). */
/* Upon returning, errorNum will contain the number of errors, */
/* errorLocs[] will contain error locations, and */
/* errorVals[] will contain error values (to be XORed with the */
/* data). */
/* Parity error is relevant only if there are other errors, and */
/* the EDC code fails parity check. */
/* NOTE! Only the first errorNum indexes of the above two arrays */
/* are relevant. The others contain garbage. */
/* Returns......: The error status. */
/* NOTE! If the error status is NO_EDC_ERROR upon return, ignore */
/* the value of the arguments. */
/*------------------------------------------------------------------------------*/
EDCstatus flDecodeEDC(char *errorSyndrom, char *errorsNum,
short errorLocs[3*T], short errorVals[3*T])
{
short noferr; /* number of errors */
short dec_parity; /* parity byte of decoded word */
short rec_parity; /* parity byte of received word */
short realsynd[SYND_LEN]; /* real syndrom calculated from residue */
short locators[T], /* error locators */
values[T]; /* error values */
short reg[SYND_LEN]; /* register for main division procedure */
int i;
RTLeightToTen(errorSyndrom, (unsigned short *)reg);
rec_parity = errorSyndrom[5] & 0xFF; /* The parity byte */
residue_to_syndrom(reg, realsynd);
noferr = decoder_for_2_errors(realsynd, locators, values);
if(noferr == 0)
return NO_EDC_ERROR; /* No error found */
if(noferr < 0) /* If an uncorrectable error was found */
return UNCORRECTABLE_ERROR;
for (i=0;i<noferr;i++)
locators[i] = N512 - 1 - locators[i];
*errorsNum = (char)convert_to_byte_patterns(locators, values, noferr, errorLocs, errorVals);
for(dec_parity=i=0; i < *errorsNum; i++)/* Calculate the parity for all the */
{ /* errors found: */
if(errorLocs[i] <= 512)
dec_parity ^= errorVals[i];
}
if(dec_parity != rec_parity)
return UNCORRECTABLE_ERROR; /* Parity error */
else
return CORRECTABLE_ERROR;
}
/*------------------------------------------------------------------------------*/
/* Function Name: flCheckAndFixEDC */
/* Purpose......: Decodes the EDC syndrom and fixs the errors if possible. */
/* block[] should contain 512 bytes of data. */
/* NOTE! Call this function only if errors where detected by */
/* syndCalc or by the ASIC module. */
/* Returns......: The error status. */
/*------------------------------------------------------------------------------*/
EDCstatus flCheckAndFixEDC(char FAR1 *block, char *syndrom, FLBoolean byteSwap)
{
char errorsNum;
short errorLocs[3*T];
short errorVals[3*T];
EDCstatus status;
status = flDecodeEDC(syndrom, &errorsNum, errorLocs, errorVals);
if(status == CORRECTABLE_ERROR) /* Fix the errors if possible */
{
int i;
for (i=0; i < errorsNum; i++)
if( (errorLocs[i] ^ byteSwap) < BLOCK_SIZE ) /* Fix only in Data Area */
block[errorLocs[i] ^ byteSwap] ^= errorVals[i];
return NO_EDC_ERROR; /* All errors are fixed */
}
else
return status; /* Uncorrectable error */
}