package yaffs2.port;
import yaffs2.utils.*;
import yaffs2.utils.factory.PrimitiveWrapperFactory;
public class yaffs_tagscompat_C {
// static {
// System.out.println("clinit tasgcomp_C");
// }
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
//
// #include "yaffs_guts.h"
// #include "yaffs_tagscompat.h"
// #include "yaffs_ecc.h"
//
// static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
// #ifdef NOTYET
// static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
// static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
// const __u8 * data,
// const yaffs_Spare * spare);
// static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
// const yaffs_Spare * spare);
// static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
// #endif
static int yaffs_CountBits(/*__u8*/ byte x)
{
int retVal;
retVal = yaffs_tagscompat_C_bitsTable.yaffs_countBitsTable[x & 0xff];
return retVal;
}
/********** Tags ECC calculations *********/
static void yaffs_CalcECC(/*const __u8*/byte[] data, int dataIndex, yaffs_Spare spare)
{
ECC_C.yaffs_ECCCalculate(data, dataIndex, spare.ecc1(), spare.ecc1Index());
ECC_C.yaffs_ECCCalculate(data, dataIndex + 256, spare.ecc2(), spare.ecc2Index());
}
static void yaffs_CalcTagsECC(yaffs_Tags tags)
{
/* Calculate an ecc */
byte[] b = tags.serialized; int bIndex = tags.offset;
int i, j;
/*unsigned*/ int ecc = 0;
/*unsigned*/ int bit = 0;
/*tags.ecc = 0;*/ tags.setEcc(0);
for (i = 0; i < 8; i++) {
for (j = 1; (j & 0xff) != 0; j <<= 1) {
bit++;
if ((b[bIndex+i] & j) != 0) {
ecc ^= bit;
}
}
}
tags.setEcc(ecc);
}
static int yaffs_CheckECCOnTags(yaffs_Tags tags)
{
/*unsigned char*/int ecc = tags.getEcc();
yaffs_CalcTagsECC(tags);
ecc ^= tags.getEcc();
if ((ecc != 0) && (Utils.intAsUnsignedInt(ecc) <= 64)) {
/* TODO: Handle the failure better. Retire? */
byte[] b = tags.serialized; int bIndex = tags.offset;
ecc--;
b[bIndex + (/*ecc / 8*/ ecc >>> 3)] ^= (1 << (ecc & 7));
/* Now recvalc the ecc */
yaffs_CalcTagsECC(tags);
return 1; /* recovered error */
} else if (ecc != 0) {
/* Wierd ecc failure value */
/* TODO Need to do somethiong here */
return -1; /* unrecovered error */
}
return 0;
}
/********** Tags **********/
static void yaffs_LoadTagsIntoSpare(yaffs_Spare sparePtr,
yaffs_Tags tagsPtr)
{
yaffs_Tags tu = tagsPtr;
yaffs_CalcTagsECC(tagsPtr);
sparePtr.setTagByte0(tu.serialized[tu.offset+0]);
sparePtr.setTagByte1(tu.serialized[tu.offset+1]);
sparePtr.setTagByte2(tu.serialized[tu.offset+2]);
sparePtr.setTagByte3(tu.serialized[tu.offset+3]);
sparePtr.setTagByte4(tu.serialized[tu.offset+4]);
sparePtr.setTagByte5(tu.serialized[tu.offset+5]);
sparePtr.setTagByte6(tu.serialized[tu.offset+6]);
sparePtr.setTagByte7(tu.serialized[tu.offset+7]);
}
static void yaffs_GetTagsFromSpare(yaffs_Device dev, yaffs_Spare sparePtr,
yaffs_Tags tagsPtr)
{
yaffs_Tags tu = tagsPtr;
int result;
tu.serialized[tu.offset+0] = sparePtr.tagByte0();
tu.serialized[tu.offset+1] = sparePtr.tagByte1();
tu.serialized[tu.offset+2] = sparePtr.tagByte2();
tu.serialized[tu.offset+3] = sparePtr.tagByte3();
tu.serialized[tu.offset+4] = sparePtr.tagByte4();
tu.serialized[tu.offset+5] = sparePtr.tagByte5();
tu.serialized[tu.offset+6] = sparePtr.tagByte6();
tu.serialized[tu.offset+7] = sparePtr.tagByte7();
result = yaffs_CheckECCOnTags(tagsPtr);
if (result > 0) {
dev.subField3.tagsEccFixed++;
} else if (result < 0) {
dev.tagsEccUnfixed++;
}
}
static void yaffs_SpareInitialise(yaffs_Spare spare)
{
Unix.memset(spare, (byte)0xFF/*, sizeof(yaffs_Spare)*/);
}
static boolean yaffs_WriteChunkToNAND(yaffs_Device dev,
int chunkInNAND, /*const __u8 **/byte[] data, int dataIndex,
yaffs_Spare spare)
{
if (chunkInNAND < dev.subField1.startBlock * dev.subField1.nChunksPerBlock) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>> yaffs chunk %d is not valid" + ydirectenv.TENDSTR),
PrimitiveWrapperFactory.get(chunkInNAND));
return Guts_H.YAFFS_FAIL;
}
dev.subField3.nPageWrites++;
return dev.subField1.writeChunkToNAND.writeChunkToNAND(dev, chunkInNAND, data, dataIndex, spare);
}
static boolean yaffs_ReadChunkFromNAND(yaffs_Device dev,
int chunkInNAND,
/*__u8 **/byte[] data, int dataIndex,
yaffs_Spare spare,
/*yaffs_ECCResult*/IntegerPointer eccResult,
boolean doErrorCorrection)
{
boolean retVal;
yaffs_Spare localSpare = new yaffs_Spare();
dev.subField3.nPageReads++;
if ((spare == null) && (data != null)) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */
spare = localSpare;
}
if (!dev.subField1.useNANDECC) {
retVal = dev.subField1.readChunkFromNAND.readChunkFromNAND(dev, chunkInNAND, data, dataIndex, spare);
if ((data != null) && doErrorCorrection) {
/* Do ECC correction */
/* Todo handle any errors */
int eccResult1, eccResult2;
/*__u8 calcEcc[3];*/ byte[] calcEcc = new byte[3];
int calcEccIndex = 0;
ECC_C.yaffs_ECCCalculate(data, dataIndex, calcEcc, calcEccIndex);
eccResult1 =
ECC_C.yaffs_ECCCorrect(data, dataIndex, spare.ecc1(), spare.ecc1Index(),
calcEcc, calcEccIndex);
ECC_C.yaffs_ECCCalculate(data, dataIndex+256, calcEcc, calcEccIndex);
eccResult2 =
ECC_C.yaffs_ECCCorrect(data, dataIndex+256,
spare.ecc2(), spare.ecc2Index(),
calcEcc, calcEccIndex);
if (eccResult1 > 0) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>>yaffs ecc error fix performed on chunk %d:0" +
ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(chunkInNAND));
dev.subField3.eccFixed++;
} else if (eccResult1 < 0) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>>yaffs ecc error unfixed on chunk %d:0" +
ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(chunkInNAND));
dev.subField3.eccUnfixed++;
}
if (eccResult2 > 0) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>>yaffs ecc error fix performed on chunk %d:1" +
ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(chunkInNAND));
dev.subField3.eccFixed++;
} else if (eccResult2 < 0) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>>yaffs ecc error unfixed on chunk %d:1" +
ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(chunkInNAND));
dev.subField3.eccUnfixed++;
}
if ((eccResult1 != 0) || (eccResult2 != 0)) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
}
if ((eccResult1 < 0) || (eccResult2 < 0))
eccResult.dereferenced = Guts_H.YAFFS_ECC_RESULT_UNFIXED;
else if ((eccResult1 > 0) || (eccResult2 > 0))
eccResult.dereferenced = Guts_H.YAFFS_ECC_RESULT_FIXED;
else
eccResult.dereferenced = Guts_H.YAFFS_ECC_RESULT_NO_ERROR;
}
} else {
/* Must allocate enough memory for spare+2*sizeof(int) */
/* for ecc results from device. */
yaffs_NANDSpare nspare = new yaffs_NANDSpare();
retVal =
dev.subField1.readChunkFromNAND.readChunkFromNAND(dev, chunkInNAND, data, dataIndex,
/*(yaffs_Spare *) & nspare*/nspare.spare);
Unix.memcpy(spare, nspare.spare/*, sizeof(yaffs_Spare)*/);
if ((data != null) && doErrorCorrection) {
if (nspare.eccres1 > 0) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>>mtd ecc error fix performed on chunk %d:0" +
ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(chunkInNAND));
} else if (nspare.eccres1 < 0) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>>mtd ecc error unfixed on chunk %d:0" +
ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(chunkInNAND));
}
if (nspare.eccres2 > 0) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>>mtd ecc error fix performed on chunk %d:1" +
ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(chunkInNAND));
} else if (nspare.eccres2 < 0) {
yportenv.T(yportenv.YAFFS_TRACE_ERROR,
("**>>mtd ecc error unfixed on chunk %d:1" +
ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(chunkInNAND));
}
if ((nspare.eccres1 != 0) || (nspare.eccres2 != 0)) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
}
if ((nspare.eccres1 < 0) || (nspare.eccres2 < 0))
eccResult.dereferenced = Guts_H.YAFFS_ECC_RESULT_UNFIXED;
else if ((nspare.eccres1 > 0) || (nspare.eccres2 > 0))
eccResult.dereferenced = Guts_H.YAFFS_ECC_RESULT_FIXED;
else
eccResult.dereferenced = Guts_H.YAFFS_ECC_RESULT_NO_ERROR;
}
}
return retVal;
}
// #ifdef NOTYET
// static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
// int chunkInNAND)
// {
//
// static int init = 0;
// static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
// static __u8 data[YAFFS_BYTES_PER_CHUNK];
// /* Might as well always allocate the larger size for */
// /* dev->useNANDECC == true; */
// static __u8 spare[sizeof(struct yaffs_NANDSpare)];
//
// dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
//
// if (!init) {
// memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
// init = 1;
// }
//
// if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
// return Guts_H.YAFFS_FAIL;
// if (memcmp(cmpbuf, spare, 16))
// return Guts_H.YAFFS_FAIL;
//
// return YAFFS_OK;
//
// }
// #endif
/*
* Functions for robustisizing
*/
static void yaffs_HandleReadDataError(yaffs_Device dev, int chunkInNAND)
{
int blockInNAND = chunkInNAND / dev.subField1.nChunksPerBlock;
/* Mark the block for retirement */
Guts_H.yaffs_GetBlockInfo(dev, blockInNAND).setNeedsRetiring(true);
yportenv.T(yportenv.YAFFS_TRACE_ERROR | yportenv.YAFFS_TRACE_BAD_BLOCKS,
("**>>Block %d marked for retirement" + ydirectenv.TENDSTR), PrimitiveWrapperFactory.get(blockInNAND));
/* TODO:
* Just do a garbage collection on the affected block
* then retire the block
* NB recursion
*/
}
// #ifdef NOTYET
// static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
// {
// }
//
// static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
// const __u8 * data,
// const yaffs_Spare * spare)
// {
// }
//
// static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
// const yaffs_Spare * spare)
// {
// }
//
// static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
// {
// int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
//
// /* Mark the block for retirement */
// yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
// /* Delete the chunk */
// yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
// }
//
// static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
// const yaffs_Spare * s0, const yaffs_Spare * s1)
// {
//
// if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
// s0->tagByte0 != s1->tagByte0 ||
// s0->tagByte1 != s1->tagByte1 ||
// s0->tagByte2 != s1->tagByte2 ||
// s0->tagByte3 != s1->tagByte3 ||
// s0->tagByte4 != s1->tagByte4 ||
// s0->tagByte5 != s1->tagByte5 ||
// s0->tagByte6 != s1->tagByte6 ||
// s0->tagByte7 != s1->tagByte7 ||
// s0->ecc1[0] != s1->ecc1[0] ||
// s0->ecc1[1] != s1->ecc1[1] ||
// s0->ecc1[2] != s1->ecc1[2] ||
// s0->ecc2[0] != s1->ecc2[0] ||
// s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
// return 0;
// }
//
// return 1;
// }
// #endif /* NOTYET */
static boolean yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device dev,
int chunkInNAND,
/*const __u8 **/byte[] data, int dataIndex,
/*const*/ yaffs_ExtendedTags
eTags)
{
yaffs_Spare spare = new yaffs_Spare();
yaffs_Tags tags = new yaffs_Tags();
yaffs_SpareInitialise(spare);
if (eTags.chunkDeleted) {
spare.setPageStatus((byte)0);
} else {
tags.setObjectID(eTags.objectId);
tags.setChunkId(eTags.chunkId);
tags.setByteCount(eTags.byteCount);
tags.setSerialNumber(eTags.serialNumber);
if ((!dev.subField1.useNANDECC) && (data != null)) {
yaffs_CalcECC(data, dataIndex, spare);
}
yaffs_LoadTagsIntoSpare(spare, tags);
}
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, dataIndex, spare);
}
static yaffs_Spare _STATIC_LOCAL_yaffs_TagsCompatabilityReadChunkWithTagsFromNAND_spareFF = new yaffs_Spare();
static boolean _STATIC_LOCAL_yaffs_TagsCompatabilityReadChunkWithTagsFromNAND_init;
static boolean yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device dev,
int chunkInNAND,
/*__u8 **/byte[] data, int dataIndex,
yaffs_ExtendedTags eTags)
{
yaffs_Spare spare = new yaffs_Spare();
yaffs_Tags tags = new yaffs_Tags();
int eccResult;
/*static yaffs_Spare spareFF;*/
/*static int init;*/
if (!_STATIC_LOCAL_yaffs_TagsCompatabilityReadChunkWithTagsFromNAND_init) {
Unix.memset(_STATIC_LOCAL_yaffs_TagsCompatabilityReadChunkWithTagsFromNAND_spareFF, (byte)0xFF/*, sizeof(spareFF)*/);
_STATIC_LOCAL_yaffs_TagsCompatabilityReadChunkWithTagsFromNAND_init = true;
}
IntegerPointer eccResultPointer = new IntegerPointer();
if (yaffs_ReadChunkFromNAND
(dev, chunkInNAND, data, dataIndex, spare, eccResultPointer, true)) {
eccResult = eccResultPointer.dereferenced;
/* eTags may be NULL */
if (eTags != null) {
boolean deleted =
(yaffs_CountBits(spare.pageStatus()) < 7);
eTags.chunkDeleted = deleted;
eTags.eccResult = eccResult;
eTags.blockBad = false; /* We're reading it */
/* therefore it is not a bad block */
eTags.chunkUsed = Unix.memcmp(_STATIC_LOCAL_yaffs_TagsCompatabilityReadChunkWithTagsFromNAND_spareFF, spare) != 0;
if (eTags.chunkUsed) {
yaffs_GetTagsFromSpare(dev, spare, tags);
eTags.objectId = tags.getObjectId();
eTags.chunkId = tags.getChunkId();
eTags.byteCount = tags.getByteCount();
eTags.serialNumber = tags.getSerialNumber();
}
}
return Guts_H.YAFFS_OK;
} else {
// eccResult = eccResultPointer.dereferenced;
return Guts_H.YAFFS_FAIL;
}
}
static boolean yaffs_TagsCompatabilityMarkNANDBlockBad(yaffs_Device dev,
int blockInNAND)
{
yaffs_Spare spare = new yaffs_Spare();
Unix.memset(spare, (byte)0xFF/*, sizeof(yaffs_Spare)*/);
spare.setBlockStatus((byte)'Y');
yaffs_WriteChunkToNAND(dev, blockInNAND * dev.subField1.nChunksPerBlock, null, 0,
spare);
yaffs_WriteChunkToNAND(dev, blockInNAND * dev.subField1.nChunksPerBlock + 1,
null, 0, spare);
return Guts_H.YAFFS_OK;
}
static yaffs_Spare _STATIC_LOCAL_yaffs_TagsCompatabilityQueryNANDBlock_spareFF = new yaffs_Spare();
static boolean _STATIC_LOCAL_yaffs_TagsCompatabilityQueryNANDBlock_init;
static boolean yaffs_TagsCompatabilityQueryNANDBlock(yaffs_Device dev,
int blockNo, /*yaffs_BlockState **/ IntegerPointer
state,
IntegerPointer sequenceNumber)
{
yaffs_Spare spare0 = new yaffs_Spare();
yaffs_Spare spare1 = new yaffs_Spare();
// static yaffs_Spare spareFF;
// static int init;
// int dummy;
if (!_STATIC_LOCAL_yaffs_TagsCompatabilityQueryNANDBlock_init) {
Unix.memset(_STATIC_LOCAL_yaffs_TagsCompatabilityQueryNANDBlock_spareFF, (byte)0xFF/*, sizeof(spareFF)*/);
_STATIC_LOCAL_yaffs_TagsCompatabilityQueryNANDBlock_init = true;
}
sequenceNumber.dereferenced = 0;
IntegerPointer dummyPointer = new IntegerPointer();
yaffs_ReadChunkFromNAND(dev, blockNo * dev.subField1.nChunksPerBlock, null, 0,
spare0, dummyPointer, true);
yaffs_ReadChunkFromNAND(dev, blockNo * dev.subField1.nChunksPerBlock + 1, null, 0,
spare1, dummyPointer, true);
// dummy = dummyPointer.dereferenced;
if (yaffs_CountBits((byte)(spare0.blockStatus() & spare1.blockStatus())) < 7)
state.dereferenced = Guts_H.YAFFS_BLOCK_STATE_DEAD;
/*else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)*/
else if (Unix.memcmp(_STATIC_LOCAL_yaffs_TagsCompatabilityQueryNANDBlock_spareFF, spare0) == 0)
state.dereferenced = Guts_H.YAFFS_BLOCK_STATE_EMPTY;
else
state.dereferenced = Guts_H.YAFFS_BLOCK_STATE_NEEDS_SCANNING;
return Guts_H.YAFFS_OK;
}
}