Esempio n. 1
0
static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
	struct mtd_concat *concat = CONCAT(mtd);
	int i, err = -EINVAL;

	if (!mtd_can_have_bb(concat->subdev[0]))
		return 0;

	if (ofs > mtd->size)
		return -EINVAL;

	for (i = 0; i < concat->num_subdev; i++) {
		struct mtd_info *subdev = concat->subdev[i];

		if (ofs >= subdev->size) {
			ofs -= subdev->size;
			continue;
		}

		err = mtd_block_markbad(subdev, ofs);
		if (!err)
			mtd->ecc_stats.badblocks++;
		break;
	}

	return err;
}
Esempio n. 2
0
/* Scheduled work - when we can't proceed without erasing a block */
static void mtdoops_workfunc_erase(struct work_struct *work)
{
	struct mtdoops_context *cxt =
			container_of(work, struct mtdoops_context, work_erase);
	struct mtd_info *mtd = cxt->mtd;
	int i = 0, j, ret, mod;

	/* We were unregistered */
	if (!mtd)
		return;

	mod = (cxt->nextpage * record_size) % mtd->erasesize;
	if (mod != 0) {
		cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / record_size);
		if (cxt->nextpage >= cxt->oops_pages)
			cxt->nextpage = 0;
	}

	while (mtd_can_have_bb(mtd)) {
		ret = mtd_block_isbad(mtd, cxt->nextpage * record_size);
		if (!ret)
			break;
		if (ret < 0) {
			printk(KERN_ERR "mtdoops: block_isbad failed, aborting\n");
			return;
		}
badblock:
		printk(KERN_WARNING "mtdoops: bad block at %08lx\n",
		       cxt->nextpage * record_size);
		i++;
		cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size);
		if (cxt->nextpage >= cxt->oops_pages)
			cxt->nextpage = 0;
		if (i == cxt->oops_pages / (mtd->erasesize / record_size)) {
			printk(KERN_ERR "mtdoops: all blocks bad!\n");
			return;
		}
	}

	for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
		ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);

	if (ret >= 0) {
		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
		       cxt->nextpage, cxt->nextcount);
		return;
	}

	if (mtd_can_have_bb(mtd) && ret == -EIO) {
		ret = mtd_block_markbad(mtd, cxt->nextpage * record_size);
		if (ret < 0) {
			printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n");
			return;
		}
	}
	goto badblock;
}
static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
	int retval;

	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);

	retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
	return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
Esempio n. 4
0
File: mtdpart.c Progetto: DFE/u-boot
static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
	struct mtd_part *part = PART(mtd);
	int res;

	ofs += part->offset;
	res = mtd_block_markbad(part->master, ofs);
	if (!res)
		mtd->ecc_stats.badblocks++;
	return res;
}
static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
	int retval;

	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
	retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
#else
	retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
#endif
	return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
void nv_def_bad_block_flag(u32 num)
{
    struct mtd_info* mtd;
    u32 sec_off;

    mtd = get_mtd_device_nm((char*)NV_DEF_SEC_NAME);
    if(!mtd)
    {
        return;
    }
    sec_off = num*mtd->erasesize;

    mtd_block_markbad(mtd,sec_off);
    put_mtd_device(mtd);
}
int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int retval;
	yaffs_trace(YAFFS_TRACE_MTD,
		"nandmtd2_mark_block_bad %d", block_no);

	retval =
	    mtd_block_markbad(mtd,
			       block_no * dev->param.chunks_per_block *
			       dev->param.total_bytes_per_chunk);

	if (retval == 0)
		return YAFFS_OK;
	else
		return YAFFS_FAIL;

}
Esempio n. 8
0
File: io.c Progetto: 383530895/linux
/**
 * ubi_io_mark_bad - mark a physical eraseblock as bad.
 * @ubi: UBI device description object
 * @pnum: the physical eraseblock number to mark
 *
 * This function returns zero in case of success and a negative error code in
 * case of failure.
 */
int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum)
{
	int err;
	struct mtd_info *mtd = ubi->mtd;

	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);

	if (ubi->ro_mode) {
		ubi_err(ubi, "read-only mode");
		return -EROFS;
	}

	if (!ubi->bad_allowed)
		return 0;

	err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
	if (err)
		ubi_err(ubi, "cannot mark PEB %d bad, error %d", pnum, err);
	return err;
}
/*===========================================================================
 
FUNCTION  FLASH_UPDATE_SHARE_REGION_INFO
 
DESCRIPTION
    update user flag,nv_mbn,and iso header info in the share region.
    This function use page to store these info, 

    Page 0: Share region Info:
           Magic:
           Sub region len:
    Page 1: Nv restore flag:
           In Used Flag Magic: 4 Byte
           Auto Restore Magic: 4Byte
           Auto Restore Flag: 
    Page 2:
          In User Flag Magic:
          MBN Magic:
          MBN Info Num:
          MBN: Version:
          MBN nv data
    Page 3:
          ISO Header Info;
          
    We use two block to implement this feature, when the first time to update this feature directly write it to the 
first available block,and then we update this info then firstly read the page info to cache, update the cache value
and then write it to another block, erase lasted block.

Author: ChenFeng 2010-3-20

RETURN VALUE
    TRUE if Op Succeed
    FALSE if Op Failure
 
SIDE EFFECTS
  None
 
===========================================================================*/
boolean flash_update_share_region_info(rgn_pos_e_type region_type,void* data)
{
    unsigned int    block_index        = 0;
    unsigned int    start_index         = 0;
    unsigned int    blk_size              = 0;
    unsigned int    blk_count            = 0;
    unsigned int    max_rgn_num    = 0;
    unsigned int    dest_block          = 0;
    unsigned int    current_block     = INVALID_BLOCK_ID;
    unsigned int    current_page      = INVALID_PAGE_ID;
    unsigned int    dest_page           = INVALID_PAGE_ID;
    rgn_hd_type* rgn_hd       = NULL;
    unsigned int   offset                    = 0;
    unsigned int   page_size             = 0;
    uint8 *   cache_buf            = NULL;
    unsigned int   start_offset           = 0;
    struct   erase_info instr;
    int retlength = 0;
    rgn_hd_type rgn_hd_1 = {0};

    /*入参条件检测*/
    if (region_type >= RGN_MAX_NUM || NULL == data)
    {
        printk(KERN_ERR "Input parm error \n");
        return FALSE;
    }

    if(NULL == flash_nand_oper_region_init(SHARE_REGION))
    {
        printk(KERN_ERR "flash_update_share_region_info init error \n");
        return FALSE;
    }

    /*Get Partition and Device Info*/
    blk_count    = child_region[SHARE_REGION].length;
    blk_size       = operation_region[SHARE_REGION].block_size;
    start_offset = operation_region[SHARE_REGION].start_addr;
    page_size   = operation_region[SHARE_REGION].page_size;
    cache_buf    = operation_region[SHARE_REGION].buffer;
    
    instr.mtd = g_mtd;
    instr.len = g_mtd->erasesize;
    instr.callback = NULL;
    instr.priv = 0;
    
    /*instr.addr*/
    for (block_index = 0; block_index < blk_count; block_index++)
    {
        offset = start_offset + blk_size * block_index;
        
        /*If the blk is bad blk or it is erase */
        if (mtd_block_isbad(g_mtd, offset))
        {
            printk(KERN_DEBUG "Find Current Block ID = 0x%x is bad block \n",(offset / blk_size));
            continue;
        }

        /*lint -e64*/
        if (!mtd_read(g_mtd, offset, page_size, &retlength, (unsigned char*)cache_buf))
        /*lint +e64*/
        {
            /*Firstly we need to check the Share Region Info,If it was a valid block
            then read corresponding page*/
            rgn_hd = (rgn_hd_type*)cache_buf;
            
            if (SHARE_RGN_MAGIC == rgn_hd->magic)
            {
                current_page = block_index * blk_size;
                max_rgn_num = rgn_hd->sub_rgn_num;
                current_block = block_index;
                printk(KERN_DEBUG "Print entery current page = 0x%x  max_rgn_num = 0x%x  \n",
                       current_page, max_rgn_num);
                break;
            }  
            else
            {
                instr.addr = offset;
                if (mtd_erase(g_mtd, &instr))
                {
                    printk(KERN_DEBUG "Current Erase error ,Mark bad block \n");
                    /* mark bad */
                    mtd_block_markbad(g_mtd, offset);
                }
                printk(KERN_DEBUG "Print nand_erase offset = 0x%x  \n", offset);
                continue;
            }
        }
        else
        {
            printk(KERN_ERR "Nand_read  error  !\n");
            return FALSE;
        }
    }

    printk(KERN_DEBUG "Print first current page = %u  \n", current_page);

    if(block_index != blk_count)
    {
        /*从 当前block 的 下一个block 分区开始寻找下一个 没使用的BLOCK*/
        dest_block = (block_index + 1) % blk_count;
    }

    /*Find the first unused block*/
    for (block_index  = 0; block_index  < blk_count; block_index++)
    {
        offset = start_offset + dest_block * blk_size;
        if (mtd_block_isbad(g_mtd, offset))
        {
                printk(KERN_DEBUG "Find Dest Block ID = 0x%x is bad block \n", (offset / blk_size));
                continue;
        }
        else
        {
            if (current_block != dest_block)
            {
                instr.addr = offset;
                if (mtd_erase(g_mtd, &instr))
                {
                    /* mark bad */
                    mtd_block_markbad(g_mtd, offset);
                    
                    dest_block = (dest_block + 1) % blk_count;
                    printk(KERN_DEBUG "Dest Erase error ,Mark bad block \n");
                    continue;
                }
                dest_page = dest_block * blk_size;
                break;
            }
        }
        dest_block = (dest_block + 1) % blk_count;
    }

    /*将当前页的数据和更新的数据分别取出写入目标BLOCK*/
    if (INVALID_PAGE_ID != dest_page)
    {   
        start_index = 0;
        /*第一次升级SHARE RGN分区  或者RGN_MAX_NUM有变化*/
        if ((unsigned int)region_type >= max_rgn_num)
        {
            offset = start_offset;
            memset(cache_buf,0xFF, page_size);  /*flash 操作buf 清为0XFF*/
            rgn_hd_1.magic = SHARE_RGN_MAGIC;
            rgn_hd_1.sub_rgn_num = RGN_MAX_NUM;
            memcpy(cache_buf,(void *)&rgn_hd_1,sizeof(rgn_hd_type));
            printk(KERN_DEBUG "Print First Dest page = %u  \n",dest_page);

            /*擦除当前BLOCK*/
            if ((INVALID_BLOCK_ID == current_block) || (0 < max_rgn_num))
            {
                offset = offset + dest_page;
            }
            else
            {
                offset = offset + current_page;
            }

            /*lint -e64*/
            if (mtd_write(g_mtd, offset, page_size, &retlength,
                (unsigned char*)cache_buf))
            /*lint +e64*/
            {
                printk(KERN_ERR "nand_write rgn_hd error  \n");
                goto FalseQuit;
            }

            memset(cache_buf,0xFF, page_size); /*flash 操作buf 清为0XFF*/
            memcpy(cache_buf,data,page_size);
            /*lint -e64*/
            if (mtd_write(g_mtd, (offset  + region_type * page_size),
                page_size, &retlength, (unsigned char*)cache_buf))
            /*lint +e64*/
            {
                printk(KERN_ERR "nand_write region page error  \n");
                goto FalseQuit;
            }
            start_index = 1;

        }

        if (INVALID_PAGE_ID != current_page && dest_page != current_page)
        {  
            offset = start_offset;
            printk(KERN_DEBUG "Print not First Dest page = %u  \n",dest_page);
            printk(KERN_DEBUG "Print last current page = %u  \n",current_page);
            for (; start_index < max_rgn_num; start_index++)            
            {
                if (start_index != region_type)
                {
                    memset(cache_buf,0xFF, page_size); /*flash 操作buf 清为0XFF*/
                    /*lint -e64*/
                    if (!mtd_read(g_mtd,(offset + current_page + start_index * page_size),
                    page_size, &retlength,(unsigned char*)cache_buf))
                    /*lint +e64*/
                    {
                        if (0 == start_index)
                        {
                            rgn_hd_type *temp_hd = NULL;
                            temp_hd = (rgn_hd_type *)cache_buf;
                            printk(KERN_DEBUG "magic = 0x%x   max_num = 0x%x \n", (unsigned int)temp_hd->magic,
                                    (unsigned int)temp_hd->sub_rgn_num);  
                        }
                        /*lint -e64*/
                        if (mtd_write(g_mtd, (offset + dest_page 
                            + start_index * page_size),
                            page_size, &retlength, (unsigned char*)cache_buf))
                        /*lint -e64*/
                        {
                            printk(KERN_DEBUG "nand_write start_index = %u  offset = 0x%x\n",
                                   start_index, (offset + dest_page
                                   + region_type * page_size));
                            continue;
                        }
                    }
                }
                else
                {
                    memset(cache_buf,0xFF, page_size); /*flash 操作buf 清为0XFF*/
                    memcpy(cache_buf,data,page_size);
                    /*lint -e64*/
                    if (mtd_write(g_mtd, (offset + dest_page + region_type * page_size),
                        page_size, &retlength, (unsigned char*)cache_buf))
                    /*lint -e64*/
                    {
                        printk(KERN_ERR "nand_write error \n");
                        goto FalseQuit;
                    }
                    printk(KERN_DEBUG "Write offset = 0x%x ! \n",
                           (offset + dest_page + region_type * page_size)); 
                }
            }

            instr.addr = offset + current_page;
            if (!mtd_erase(g_mtd, &instr))
            {
                printk(KERN_DEBUG "nand_erase offset = 0x%x ! \n",(offset + current_page)); 
            }
            else
            {
                printk(KERN_DEBUG "Last Erase current error ,Mark bad block \n");
                /* mark bad */
                mtd_block_markbad(g_mtd, offset);
                goto FalseQuit;
            } 
        }
        else if (dest_page == current_page)
        {
            printk(KERN_DEBUG "Error dest_page == current_page offset = 0x%x  \n", current_page);
            goto FalseQuit;
        }
        
        flash_nand_oper_region_close(SHARE_REGION);
        return TRUE;
    }
FalseQuit:
    printk(KERN_ERR "flash_update_share_region_info error \n");
    flash_nand_oper_region_close(SHARE_REGION);
    return FALSE;
}
Esempio n. 10
0
static int write_block(struct mtd_info* mtd, uint64_t* offset, unsigned char* buf, unsigned char* tmpbuf, int has_oob)
{

    int ret=0;
    int retry;
    int markbad=0;
next:
    markbad = 0;
    ret = mtd_block_isbad(mtd, *offset);
    if(ret < 0) {
        printf("\nFWU bad block detection failure: off 0x%012llX\n",
               *offset);
        return -1;
    }
    else if (ret == 1) {
        printf("\nFWU bad block detected: off 0x%012llX\n",
               *offset);
        *offset += mtd->erasesize;
        goto next;
    }

    for(retry=0; (retry<3); retry++) {
        printf("FWU rewriting block: off 0x%012llX / %lldM %s %d\t\t\r",
               *offset,
               *offset / 1024 / 1024,
               retry == 0 ? "" : " \t(again)\n", retry);

        if (retry) {
            ret = mtd_erase1(mtd, *offset);
            if(ret < 0) {
                printf("\nFWU erase err: off 0x%012llX ret %d\n",
                       *offset, ret);
                markbad = 1;
                continue;
            }
        }

        if (!has_oob)
            ret = mtd_write(mtd, *offset, buf, mtd->erasesize);
        else {
            int tmp;
            for (tmp=0; tmp < (mtd->erasesize / mtd->writesize); tmp++ ) {
                ret = mtd_writeoob(mtd,
                                   *offset + (tmp * mtd->writesize),
                                   buf + tmp * (mtd->writesize + mtd->oobsize),
                                   mtd->writesize);
                if (ret<0)
                    break;
            }
        }

        if(ret < 0) {
            printf("\nFWU write err: off 0x%012llX ret %d\n",
                   *offset, ret);
            markbad = 1;
            continue;
        }

        /* read back to force hardware CRC checks */
        ret = mtd_read(mtd, *offset, tmpbuf, mtd->erasesize);
        if(ret < 0) {
            printf("\nFWU checkread err: off 0x%012llX ret %d\n",
                   *offset, ret);
            markbad = 1;
            continue;
        }
        *offset += mtd->erasesize;
        break;
    }

    if (markbad) {
        printf("\nFWU failed to overwrite block, skipping it and marking bad: off 0x%012llX ret %d\n",
               *offset, ret);
        mtd_erase1(mtd, *offset); /* Try to make sure block is somewhat clean */
        mtd_block_markbad(mtd, *offset);
        *offset += mtd->erasesize;
        goto next;
    }
    return 0;
}
Esempio n. 11
0
static int fwu_tftp_cb(uint32_t off, u8* buf, size_t len, int last, void* priv)
{
    int ret;
    struct fwu_tftp_ctx *ctx = (struct fwu_tftp_ctx*)priv;

    if(ctx == NULL) {
        return -EINVAL;
    }

    struct mtd_info *mtd = ctx->mtd;

    BUG_ON(ctx->last);
    ctx->last = last;

    ret = 0;
    while(len > 0) {
        size_t len1 = MIN(mtd->erasesize - ctx->block_sz, len);
        memcpy(&ctx->block[ctx->block_sz], buf, len1);

        ctx->block_sz += len1;
        buf += len1;
        len -= len1;

        if((ctx->block_sz == mtd->erasesize) || last) {

            int retry;
            int bad = 0;

            ret = mtd_block_isbad(mtd, ctx->flash_offset);
            if(ret < 0) {
                printf("\nFWU bad block detection failure: off 0x%012llX\n",
                       ctx->flash_offset);
                goto err;
            }
            else if (ret == 1) {
                printf("\nFWU bad block detected: off 0x%012llX\n",
                       ctx->flash_offset);
                bad = 1;
                ret = 0;
            }

            for(retry=0; ((retry<3) && (ctx->block_sz>0)); retry++) {
                printf("FWU rewriting block: off 0x%012llX / %lldM %s%s %d\t\t\r",
                       ctx->flash_offset,
                       ctx->flash_offset / 1024 / 1024,
                       bad ? " \t(BAD)\n" : "",
                       retry == 0 ? "" : " \t(again)\n", retry);

                if (retry) {
                    ret = mtd_erase1(mtd, ctx->flash_offset);
                    if(ret < 0) {
                        printf("\nFWU erase err: off 0x%012llX ret %d\n",
                               ctx->flash_offset, ret);
                        continue;
                    }
                }

                if (ctx->oob==0)
                    ret = mtd_write(mtd, ctx->flash_offset, ctx->block, mtd->erasesize);
                else {
                    int tmp;
                    for (tmp=0; tmp < (mtd->erasesize / mtd->writesize); tmp ++ ) {
                        ret = mtd_writeoob(mtd,
                                           ctx->flash_offset + (tmp * mtd->writesize),
                                           ctx->block + tmp * (mtd->writesize + mtd->oobsize),
                                           mtd->writesize);
                        if (ret<0)
                            break;
                    }
                }

                if(ret < 0) {
                    printf("\nFWU write err: off 0x%012llX ret %d\n",
                           ctx->flash_offset, ret);
                    continue;
                }

                /* read back to force hardware CRC checks */
                ret = mtd_read(mtd, ctx->flash_offset, ctx->block, mtd->erasesize);
                if(ret < 0) {
                    printf("\nFWU checkread err: off 0x%012llX ret %d\n",
                           ctx->flash_offset, ret);
                    continue;
                }
                ctx->flash_offset += mtd->erasesize;
                ctx->block_sz = 0;
            }

            if(ctx->block_sz > 0) {
                printf("\nFWU failed to overwrite block, skipping it and marking bad: off 0x%012llX ret %d\n",
                       ctx->flash_offset, ret);
                mtd_erase1(mtd, ctx->flash_offset); /* Don't allow just to screw us */
                mtd_block_markbad(mtd, ctx->flash_offset);
                ctx->flash_offset += mtd->erasesize;
            }
        }
    }

err:
    return ret;
}
Esempio n. 12
0
int mtd_ioctl(struct cdev *cdev, int request, void *buf)
{
	int ret = 0;
	struct mtd_info *mtd = cdev->priv;
	struct mtd_info_user *user = buf;
#if (defined(CONFIG_NAND_ECC_HW) || defined(CONFIG_NAND_ECC_SOFT))
	struct mtd_ecc_stats *ecc = buf;
#endif
	struct region_info_user *reg = buf;
#ifdef CONFIG_MTD_WRITE
	struct erase_info_user *ei = buf;
#endif
	loff_t *offset = buf;

	switch (request) {
	case MEMGETBADBLOCK:
		dev_dbg(cdev->dev, "MEMGETBADBLOCK: 0x%08llx\n", *offset);
		ret = mtd_block_isbad(mtd, *offset);
		break;
#ifdef CONFIG_MTD_WRITE
	case MEMSETBADBLOCK:
		dev_dbg(cdev->dev, "MEMSETBADBLOCK: 0x%08llx\n", *offset);
		ret = mtd_block_markbad(mtd, *offset);
		break;
	case MEMERASE:
		ret = mtd_op_erase(cdev, ei->length, ei->start + cdev->offset);
		break;
#endif
	case MEMGETINFO:
		user->type	= mtd->type;
		user->flags	= mtd->flags;
		user->size	= mtd->size;
		user->erasesize	= mtd->erasesize;
		user->writesize	= mtd->writesize;
		user->oobsize	= mtd->oobsize;
		user->subpagesize = mtd->writesize >> mtd->subpage_sft;
		user->mtd	= mtd;
		/* The below fields are obsolete */
		user->ecctype	= -1;
		user->eccsize	= 0;
		break;
#if (defined(CONFIG_NAND_ECC_HW) || defined(CONFIG_NAND_ECC_SOFT))
	case ECCGETSTATS:
		ecc->corrected = mtd->ecc_stats.corrected;
		ecc->failed = mtd->ecc_stats.failed;
		ecc->badblocks = mtd->ecc_stats.badblocks;
		ecc->bbtblocks = mtd->ecc_stats.bbtblocks;
		break;
#endif
	case MEMGETREGIONINFO:
		if (cdev->mtd) {
			unsigned long size = cdev->size;
			reg->offset = cdev->offset;
			reg->erasesize = cdev->mtd->erasesize;
			reg->numblocks = size / reg->erasesize;
			reg->regionindex = cdev->mtd->index;
		}
		break;
	default:
		ret = -EINVAL;
	}

	return ret;
}