1*0e8cc8bdSWilliam Juul /* 2*0e8cc8bdSWilliam Juul * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 3*0e8cc8bdSWilliam Juul * 4*0e8cc8bdSWilliam Juul * Copyright (C) 2002-2007 Aleph One Ltd. 5*0e8cc8bdSWilliam Juul * for Toby Churchill Ltd and Brightstar Engineering 6*0e8cc8bdSWilliam Juul * 7*0e8cc8bdSWilliam Juul * Created by Charles Manning <charles@aleph1.co.uk> 8*0e8cc8bdSWilliam Juul * 9*0e8cc8bdSWilliam Juul * This program is free software; you can redistribute it and/or modify 10*0e8cc8bdSWilliam Juul * it under the terms of the GNU General Public License version 2 as 11*0e8cc8bdSWilliam Juul * published by the Free Software Foundation. 12*0e8cc8bdSWilliam Juul */ 13*0e8cc8bdSWilliam Juul 14*0e8cc8bdSWilliam Juul /* mtd interface for YAFFS2 */ 15*0e8cc8bdSWilliam Juul 16*0e8cc8bdSWilliam Juul const char *yaffs_mtdif2_c_version = 17*0e8cc8bdSWilliam Juul "$Id: yaffs_mtdif2.c,v 1.17 2007/02/14 01:09:06 wookey Exp $"; 18*0e8cc8bdSWilliam Juul 19*0e8cc8bdSWilliam Juul #include "yportenv.h" 20*0e8cc8bdSWilliam Juul 21*0e8cc8bdSWilliam Juul 22*0e8cc8bdSWilliam Juul #include "yaffs_mtdif2.h" 23*0e8cc8bdSWilliam Juul 24*0e8cc8bdSWilliam Juul #include "linux/mtd/mtd.h" 25*0e8cc8bdSWilliam Juul #include "linux/types.h" 26*0e8cc8bdSWilliam Juul #include "linux/time.h" 27*0e8cc8bdSWilliam Juul 28*0e8cc8bdSWilliam Juul #include "yaffs_packedtags2.h" 29*0e8cc8bdSWilliam Juul 30*0e8cc8bdSWilliam Juul int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, 31*0e8cc8bdSWilliam Juul const __u8 * data, 32*0e8cc8bdSWilliam Juul const yaffs_ExtendedTags * tags) 33*0e8cc8bdSWilliam Juul { 34*0e8cc8bdSWilliam Juul struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 35*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 36*0e8cc8bdSWilliam Juul struct mtd_oob_ops ops; 37*0e8cc8bdSWilliam Juul #else 38*0e8cc8bdSWilliam Juul size_t dummy; 39*0e8cc8bdSWilliam Juul #endif 40*0e8cc8bdSWilliam Juul int retval = 0; 41*0e8cc8bdSWilliam Juul 42*0e8cc8bdSWilliam Juul loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 43*0e8cc8bdSWilliam Juul 44*0e8cc8bdSWilliam Juul yaffs_PackedTags2 pt; 45*0e8cc8bdSWilliam Juul 46*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_MTD, 47*0e8cc8bdSWilliam Juul (TSTR 48*0e8cc8bdSWilliam Juul ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" 49*0e8cc8bdSWilliam Juul TENDSTR), chunkInNAND, data, tags)); 50*0e8cc8bdSWilliam Juul 51*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 52*0e8cc8bdSWilliam Juul if (tags) 53*0e8cc8bdSWilliam Juul yaffs_PackTags2(&pt, tags); 54*0e8cc8bdSWilliam Juul else 55*0e8cc8bdSWilliam Juul BUG(); /* both tags and data should always be present */ 56*0e8cc8bdSWilliam Juul 57*0e8cc8bdSWilliam Juul if (data) { 58*0e8cc8bdSWilliam Juul ops.mode = MTD_OOB_AUTO; 59*0e8cc8bdSWilliam Juul ops.ooblen = sizeof(pt); 60*0e8cc8bdSWilliam Juul ops.len = dev->nDataBytesPerChunk; 61*0e8cc8bdSWilliam Juul ops.ooboffs = 0; 62*0e8cc8bdSWilliam Juul ops.datbuf = (__u8 *)data; 63*0e8cc8bdSWilliam Juul ops.oobbuf = (void *)&pt; 64*0e8cc8bdSWilliam Juul retval = mtd->write_oob(mtd, addr, &ops); 65*0e8cc8bdSWilliam Juul } else 66*0e8cc8bdSWilliam Juul BUG(); /* both tags and data should always be present */ 67*0e8cc8bdSWilliam Juul #else 68*0e8cc8bdSWilliam Juul if (tags) { 69*0e8cc8bdSWilliam Juul yaffs_PackTags2(&pt, tags); 70*0e8cc8bdSWilliam Juul } 71*0e8cc8bdSWilliam Juul 72*0e8cc8bdSWilliam Juul if (data && tags) { 73*0e8cc8bdSWilliam Juul if (dev->useNANDECC) 74*0e8cc8bdSWilliam Juul retval = 75*0e8cc8bdSWilliam Juul mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, 76*0e8cc8bdSWilliam Juul &dummy, data, (__u8 *) & pt, NULL); 77*0e8cc8bdSWilliam Juul else 78*0e8cc8bdSWilliam Juul retval = 79*0e8cc8bdSWilliam Juul mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, 80*0e8cc8bdSWilliam Juul &dummy, data, (__u8 *) & pt, NULL); 81*0e8cc8bdSWilliam Juul } else { 82*0e8cc8bdSWilliam Juul if (data) 83*0e8cc8bdSWilliam Juul retval = 84*0e8cc8bdSWilliam Juul mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, 85*0e8cc8bdSWilliam Juul data); 86*0e8cc8bdSWilliam Juul if (tags) 87*0e8cc8bdSWilliam Juul retval = 88*0e8cc8bdSWilliam Juul mtd->write_oob(mtd, addr, mtd->oobsize, &dummy, 89*0e8cc8bdSWilliam Juul (__u8 *) & pt); 90*0e8cc8bdSWilliam Juul 91*0e8cc8bdSWilliam Juul } 92*0e8cc8bdSWilliam Juul #endif 93*0e8cc8bdSWilliam Juul 94*0e8cc8bdSWilliam Juul if (retval == 0) 95*0e8cc8bdSWilliam Juul return YAFFS_OK; 96*0e8cc8bdSWilliam Juul else 97*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 98*0e8cc8bdSWilliam Juul } 99*0e8cc8bdSWilliam Juul 100*0e8cc8bdSWilliam Juul int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, 101*0e8cc8bdSWilliam Juul __u8 * data, yaffs_ExtendedTags * tags) 102*0e8cc8bdSWilliam Juul { 103*0e8cc8bdSWilliam Juul struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 104*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 105*0e8cc8bdSWilliam Juul struct mtd_oob_ops ops; 106*0e8cc8bdSWilliam Juul #endif 107*0e8cc8bdSWilliam Juul size_t dummy; 108*0e8cc8bdSWilliam Juul int retval = 0; 109*0e8cc8bdSWilliam Juul 110*0e8cc8bdSWilliam Juul loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; 111*0e8cc8bdSWilliam Juul 112*0e8cc8bdSWilliam Juul yaffs_PackedTags2 pt; 113*0e8cc8bdSWilliam Juul 114*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_MTD, 115*0e8cc8bdSWilliam Juul (TSTR 116*0e8cc8bdSWilliam Juul ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" 117*0e8cc8bdSWilliam Juul TENDSTR), chunkInNAND, data, tags)); 118*0e8cc8bdSWilliam Juul 119*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 120*0e8cc8bdSWilliam Juul if (data && !tags) 121*0e8cc8bdSWilliam Juul retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, 122*0e8cc8bdSWilliam Juul &dummy, data); 123*0e8cc8bdSWilliam Juul else if (tags) { 124*0e8cc8bdSWilliam Juul ops.mode = MTD_OOB_AUTO; 125*0e8cc8bdSWilliam Juul ops.ooblen = sizeof(pt); 126*0e8cc8bdSWilliam Juul ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt); 127*0e8cc8bdSWilliam Juul ops.ooboffs = 0; 128*0e8cc8bdSWilliam Juul ops.datbuf = data; 129*0e8cc8bdSWilliam Juul ops.oobbuf = dev->spareBuffer; 130*0e8cc8bdSWilliam Juul retval = mtd->read_oob(mtd, addr, &ops); 131*0e8cc8bdSWilliam Juul } 132*0e8cc8bdSWilliam Juul #else 133*0e8cc8bdSWilliam Juul if (data && tags) { 134*0e8cc8bdSWilliam Juul if (dev->useNANDECC) { 135*0e8cc8bdSWilliam Juul retval = 136*0e8cc8bdSWilliam Juul mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, 137*0e8cc8bdSWilliam Juul &dummy, data, dev->spareBuffer, 138*0e8cc8bdSWilliam Juul NULL); 139*0e8cc8bdSWilliam Juul } else { 140*0e8cc8bdSWilliam Juul retval = 141*0e8cc8bdSWilliam Juul mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, 142*0e8cc8bdSWilliam Juul &dummy, data, dev->spareBuffer, 143*0e8cc8bdSWilliam Juul NULL); 144*0e8cc8bdSWilliam Juul } 145*0e8cc8bdSWilliam Juul } else { 146*0e8cc8bdSWilliam Juul if (data) 147*0e8cc8bdSWilliam Juul retval = 148*0e8cc8bdSWilliam Juul mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, 149*0e8cc8bdSWilliam Juul data); 150*0e8cc8bdSWilliam Juul if (tags) 151*0e8cc8bdSWilliam Juul retval = 152*0e8cc8bdSWilliam Juul mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, 153*0e8cc8bdSWilliam Juul dev->spareBuffer); 154*0e8cc8bdSWilliam Juul } 155*0e8cc8bdSWilliam Juul #endif 156*0e8cc8bdSWilliam Juul 157*0e8cc8bdSWilliam Juul memcpy(&pt, dev->spareBuffer, sizeof(pt)); 158*0e8cc8bdSWilliam Juul 159*0e8cc8bdSWilliam Juul if (tags) 160*0e8cc8bdSWilliam Juul yaffs_UnpackTags2(tags, &pt); 161*0e8cc8bdSWilliam Juul 162*0e8cc8bdSWilliam Juul if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) 163*0e8cc8bdSWilliam Juul tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; 164*0e8cc8bdSWilliam Juul 165*0e8cc8bdSWilliam Juul if (retval == 0) 166*0e8cc8bdSWilliam Juul return YAFFS_OK; 167*0e8cc8bdSWilliam Juul else 168*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 169*0e8cc8bdSWilliam Juul } 170*0e8cc8bdSWilliam Juul 171*0e8cc8bdSWilliam Juul int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) 172*0e8cc8bdSWilliam Juul { 173*0e8cc8bdSWilliam Juul struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 174*0e8cc8bdSWilliam Juul int retval; 175*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_MTD, 176*0e8cc8bdSWilliam Juul (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); 177*0e8cc8bdSWilliam Juul 178*0e8cc8bdSWilliam Juul retval = 179*0e8cc8bdSWilliam Juul mtd->block_markbad(mtd, 180*0e8cc8bdSWilliam Juul blockNo * dev->nChunksPerBlock * 181*0e8cc8bdSWilliam Juul dev->nDataBytesPerChunk); 182*0e8cc8bdSWilliam Juul 183*0e8cc8bdSWilliam Juul if (retval == 0) 184*0e8cc8bdSWilliam Juul return YAFFS_OK; 185*0e8cc8bdSWilliam Juul else 186*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 187*0e8cc8bdSWilliam Juul 188*0e8cc8bdSWilliam Juul } 189*0e8cc8bdSWilliam Juul 190*0e8cc8bdSWilliam Juul int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, 191*0e8cc8bdSWilliam Juul yaffs_BlockState * state, int *sequenceNumber) 192*0e8cc8bdSWilliam Juul { 193*0e8cc8bdSWilliam Juul struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); 194*0e8cc8bdSWilliam Juul int retval; 195*0e8cc8bdSWilliam Juul 196*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_MTD, 197*0e8cc8bdSWilliam Juul (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); 198*0e8cc8bdSWilliam Juul retval = 199*0e8cc8bdSWilliam Juul mtd->block_isbad(mtd, 200*0e8cc8bdSWilliam Juul blockNo * dev->nChunksPerBlock * 201*0e8cc8bdSWilliam Juul dev->nDataBytesPerChunk); 202*0e8cc8bdSWilliam Juul 203*0e8cc8bdSWilliam Juul if (retval) { 204*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); 205*0e8cc8bdSWilliam Juul 206*0e8cc8bdSWilliam Juul *state = YAFFS_BLOCK_STATE_DEAD; 207*0e8cc8bdSWilliam Juul *sequenceNumber = 0; 208*0e8cc8bdSWilliam Juul } else { 209*0e8cc8bdSWilliam Juul yaffs_ExtendedTags t; 210*0e8cc8bdSWilliam Juul nandmtd2_ReadChunkWithTagsFromNAND(dev, 211*0e8cc8bdSWilliam Juul blockNo * 212*0e8cc8bdSWilliam Juul dev->nChunksPerBlock, NULL, 213*0e8cc8bdSWilliam Juul &t); 214*0e8cc8bdSWilliam Juul 215*0e8cc8bdSWilliam Juul if (t.chunkUsed) { 216*0e8cc8bdSWilliam Juul *sequenceNumber = t.sequenceNumber; 217*0e8cc8bdSWilliam Juul *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; 218*0e8cc8bdSWilliam Juul } else { 219*0e8cc8bdSWilliam Juul *sequenceNumber = 0; 220*0e8cc8bdSWilliam Juul *state = YAFFS_BLOCK_STATE_EMPTY; 221*0e8cc8bdSWilliam Juul } 222*0e8cc8bdSWilliam Juul } 223*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_MTD, 224*0e8cc8bdSWilliam Juul (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber, 225*0e8cc8bdSWilliam Juul *state)); 226*0e8cc8bdSWilliam Juul 227*0e8cc8bdSWilliam Juul if (retval == 0) 228*0e8cc8bdSWilliam Juul return YAFFS_OK; 229*0e8cc8bdSWilliam Juul else 230*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 231*0e8cc8bdSWilliam Juul } 232*0e8cc8bdSWilliam Juul 233