140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project/*
240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * YAFFS: Yet another FFS. A NAND-flash specific file system.
340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *
440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * Copyright (C) 2002 Aleph One Ltd.
540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *   for Toby Churchill Ltd and Brightstar Engineering
640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *
740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * Created by Charles Manning <charles@aleph1.co.uk>
840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *
940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * This program is free software; you can redistribute it and/or modify
1040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * it under the terms of the GNU General Public License version 2 as
1140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * published by the Free Software Foundation.
1240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *
1340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project */
1440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
1540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectconst char *yaffs_nand_c_version =
1640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project    "$Id: yaffs_nand.c,v 1.4 2006/10/13 08:52:49 charles Exp $";
1740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
1840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project#include "yaffs_nand.h"
1940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project#include "yaffs_tagscompat.h"
2040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project#include "yaffs_tagsvalidity.h"
2140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
2240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
2340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
2440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project					   __u8 * buffer,
2540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project					   yaffs_ExtendedTags * tags)
2640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
2740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int result;
2840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	yaffs_ExtendedTags localTags;
2940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
3040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
3140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
3240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	/* If there are no tags provided, use local tags to get prioritised gc working */
3340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(!tags)
3440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		tags = &localTags;
3540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
3640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if (dev->readChunkWithTagsFromNAND)
3740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
3840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project						      tags);
3940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	else
4040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
4140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project									realignedChunkInNAND,
4240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project									buffer,
4340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project									tags);
4440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(tags &&
4540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	   tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
4640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
4740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
4840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project                yaffs_HandleChunkError(dev,bi);
4940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
5040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
5140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return result;
5240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
5340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
5440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
5540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project						   int chunkInNAND,
5640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project						   const __u8 * buffer,
5740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project						   yaffs_ExtendedTags * tags)
5840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
5940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	chunkInNAND -= dev->chunkOffset;
6040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
6140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
6240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if (tags) {
6340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		tags->sequenceNumber = dev->sequenceNumber;
6440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		tags->chunkUsed = 1;
6540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		if (!yaffs_ValidateTags(tags)) {
6640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			T(YAFFS_TRACE_ERROR,
6740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			  (TSTR("Writing uninitialised tags" TENDSTR)));
6840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			YBUG();
6940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		}
7040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		T(YAFFS_TRACE_WRITE,
7140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		  (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
7240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		   tags->objectId, tags->chunkId));
7340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	} else {
7440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
7540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		YBUG();
7640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
7740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
7840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if (dev->writeChunkWithTagsToNAND)
7940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
8040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project						     tags);
8140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	else
8240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
8340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project								       chunkInNAND,
8440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project								       buffer,
8540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project								       tags);
8640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
8740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
8840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
8940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
9040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	blockNo -= dev->blockOffset;
9140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
9240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project;
9340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if (dev->markNANDBlockBad)
9440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return dev->markNANDBlockBad(dev, blockNo);
9540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	else
9640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
9740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
9840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
9940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_QueryInitialBlockState(yaffs_Device * dev,
10040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project						 int blockNo,
10140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project						 yaffs_BlockState * state,
10240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project						 unsigned *sequenceNumber)
10340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
10440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	blockNo -= dev->blockOffset;
10540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
10640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if (dev->queryNANDBlock)
10740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
10840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	else
10940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
11040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project							     state,
11140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project							     sequenceNumber);
11240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
11340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
11440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
11540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
11640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				  int blockInNAND)
11740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
11840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int result;
11940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
12040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	blockInNAND -= dev->blockOffset;
12140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
12240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
12340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->nBlockErasures++;
12440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	result = dev->eraseBlockInNAND(dev, blockInNAND);
12540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
12640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	/* If at first we don't succeed, try again *once*.*/
12740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if (!result)
12840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		result = dev->eraseBlockInNAND(dev, blockInNAND);
12940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return result;
13040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
13140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
13240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
13340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
13440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return dev->initialiseNAND(dev);
13540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
13640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
13740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
13840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
139