On Wednesday 03 August 2005 07:00, Artis Kugevics
artis@mikrotik.com wrote:
> I wonder, at what oob offset yaffs2 out-of-band data is placed
> for curent yaffs2 users? This offset is taken from default
> nand_oobinfo structure in MTD. If not overriden, then it is
> nand_oob_64 in mtd/nand/nand_base.c, which sets offset to 2
> (oobfree = {{2,38}}).
>
> I personally, had to modify yaffs2 source, for it to work with
> such setting. Modification is necessarry, because that
> mtd->read_oob() call returns oob data from offset 0 (and not
> from offset 2, as specified by nand_oobinfo structure). My
> patch is attached for reference.
Attached is the hacking I did to get this to work for me.
I have yaffs1 call mtd->read_oob normally. Then in yaffs_mtdif2.c
I hack the call to mtd->read_oob to pass a null 'retlen'
pointer.
Then in MTD nand_base.c, I hacked the nand_read_oob function to
not 'do-the-wrong-thing' when it is called with a null retlen.
So I'm overloading 'retlen' and using it as a flag --- yes this
is a hack, but so is MTD ;)
I don't understand why this isn't broken for everyone?
I don't know how yaffs2 ever works with the stock MTD code.
See attached files/functions.
-imcd
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif.c NAND mtd wrapper functions.
*
* Copyright (C) 2002 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.
*
*/
// mtd interface for YAFFS2
const char *yaffs_mtdif2_c_version = "$Id: yaffs_mtdif2.c,v 1.1.1.3 2005/07/26 20:22:06 ian Exp $";
#ifdef CONFIG_YAFFS_MTD_ENABLED
#include "yportenv.h"
#include "yaffs_mtdif2.h"
#include "linux/mtd/mtd.h"
#include "linux/types.h"
#include "linux/time.h"
#include "yaffs_packedtags2.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" TENDSTR),chunkInNAND,data,tags));
if(tags)
{
yaffs_PackTags2(&pt,tags);
}
#ifndef CONFIG_YAFFS_USE_OLD_MTD
if(data && tags)
{
if(dev->useNANDECC)
retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,(__u8 *)&pt,NULL);
else
retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,(__u8 *)&pt,NULL);
}
else
{
#endif
if(data)
retval = mtd->write(mtd,addr,dev->nBytesPerChunk,&dummy,data);
#if 1 //BSE: this call does not do autoplace and should not be used
if(tags) {
printk(KERN_ERR "yaffs2: attempt to write_oob!\n");
return YAFFS_FAIL;
}
#else
if(tags)
retval = mtd->write_oob(mtd,addr,mtd->oobsize,&dummy,(__u8 *)&pt);
#endif
#ifndef CONFIG_YAFFS_USE_OLD_MTD
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p" TENDSTR),chunkInNAND,data,tags));
#ifndef CONFIG_YAFFS_USE_OLD_MTD
if(data && tags)
{
if(dev->useNANDECC)
{
retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,dev->spareBuffer,NULL);
}
else
{
retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,dev->spareBuffer,NULL);
}
}
else
{
#endif
if(data)
retval = mtd->read(mtd,addr,dev->nBytesPerChunk,&dummy,data);
#if 1 //BSE: fix for MTD API, see mtd's nand_read_oob function
if(tags)
retval = mtd->read_oob(mtd,addr,mtd->oobsize,0,dev->spareBuffer);
#else
if(tags)
retval = mtd->read_oob(mtd,addr,mtd->oobsize,&dummy,dev->spareBuffer);
#endif
#ifndef CONFIG_YAFFS_USE_OLD_MTD
}
#endif
memcpy(&pt,dev->spareBuffer,sizeof(pt));
if(tags)
yaffs_UnpackTags2(tags,&pt);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR),blockNo));
retval = mtd->block_markbad(mtd,blockNo * dev->nChunksPerBlock * dev->nBytesPerChunk);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR),blockNo));
#if 1 //++BSE: fix for MTD API
retval = mtd->block_isbad(mtd,
blockNo * dev->nChunksPerBlock * dev->nBytesPerChunk);
#else
retval = mtd->block_isbad(mtd,blockNo* dev->nChunksPerBlock * dev->nBytesPerChunk);
#endif
if(retval)
{
T(YAFFS_TRACE_MTD,(TSTR("block is bad" TENDSTR)));
*state = YAFFS_BLOCK_STATE_DEAD;
*sequenceNumber = 0;
}
else
{
yaffs_ExtendedTags t;
nandmtd2_ReadChunkWithTagsFromNAND(dev,blockNo * dev->nChunksPerBlock,NULL, &t);
if(t.chunkUsed)
{
*sequenceNumber = t.sequenceNumber;
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
}
else
{
*sequenceNumber = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
T(YAFFS_TRACE_MTD,(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,*state));
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
#endif
/**
* nand_read_oob - [MTD Interface] NAND read out-of-band
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
*
* NAND read out-of-band data from the spare area
*/
static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
{
int i, col, page, chipnr;
struct nand_chip *this = mtd->priv;
int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
/* Shift to get page */
page = (int)(from >> this->page_shift);
chipnr = (int)(from >> this->chip_shift);
/* Mask to get column */
col = from & (mtd->oobsize - 1);
#if 1 // BSE feature/fix for yaffs
/* This MTD function normally provides raw ECC data.
* YAFFS2 needs autoplacement when reading the ECC.
* We use a NULL retlen to indicate need for autoplacement.
*/
if (!retlen) {
/* do zerocopy autoplace by adjusting the column
* and trimming the length.
*/
retlen = &i;
col += this->autooob->oobfree[0][0];
if (len > this->autooob->oobfree[0][1]) {
len = this->autooob->oobfree[0][1];
}
//printk("rd_oob: from %#llx page %d, col %d, len %d\n", from, page, col, len);
}
#endif
/* Initialize return length value */
*retlen = 0;
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
*retlen = 0;
return -EINVAL;
}
/* Grab the lock and see if the device is available */
nand_get_device (this, mtd , FL_READING);
/* Select the NAND device */
this->select_chip(mtd, chipnr);
/* Send the read command */
this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask);
/*
* Read the data, if we read more than one page
* oob data, let the device transfer the data !
*/
i = 0;
while (i < len) {
int thislen = mtd->oobsize - col;
thislen = min_t(int, thislen, len);
this->read_buf(mtd, &buf[i], thislen);
i += thislen;
/* Apply delay or wait for ready/busy pin
* Do this before the AUTOINCR check, so no problems
* arise if a chip which does auto increment
* is marked as NOAUTOINCR by the board driver.
*/
if (!this->dev_ready)
udelay (this->chip_delay);
else
nand_wait_ready(mtd);
/* Read more ? */
if (i < len) {
page++;
col = 0;
/* Check, if we cross a chip boundary */
if (!(page & this->pagemask)) {
chipnr++;
this->select_chip(mtd, -1);
this->select_chip(mtd, chipnr);
}
/* Check, if the chip supports auto page increment
* or if we have hit a block boundary.
*/
if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
/* For subsequent page reads set offset to 0 */
this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
}
}
}
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
/* Return happy */
*retlen = len;
return 0;
}