Re: [Yaffs] yaffs2 oob offset problem

Top Page
Attachments:
Message as email
+ (text/plain)
+ yaffs_mtdif2.c (text/x-csrc)
+ mtd_read_oob.c (text/x-csrc)
Delete this message
Reply to this message
Author: Ian McDonnell
Date:  
To: Artis Kugevics, yaffs
Subject: Re: [Yaffs] yaffs2 oob offset problem
On Wednesday 03 August 2005 07:00, Artis Kugevics
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 <>
*
* 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;
}