2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2007 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 /* mtd interface for YAFFS2 */
16 const char *yaffs_mtdif2_c_version
=
17 "$Id: yaffs_mtdif2.c,v 1.20 2008-05-05 07:58:58 charles Exp $";
22 #include "yaffs_mtdif2.h"
24 #include "linux/mtd/mtd.h"
25 #include "linux/types.h"
26 #include "linux/time.h"
28 #include "yaffs_packedtags2.h"
30 /* NB For use with inband tags....
31 * We assume that the data buffer is of size totalBytersPerChunk so that we can also
32 * use it to load the tags.
34 int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device
* dev
, int chunkInNAND
,
36 const yaffs_ExtendedTags
* tags
)
38 struct mtd_info
*mtd
= (struct mtd_info
*)(dev
->genericDevice
);
39 #if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
40 struct mtd_oob_ops ops
;
52 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
53 TENDSTR
), chunkInNAND
, data
, tags
));
56 addr
= ((loff_t
) chunkInNAND
) * dev
->totalBytesPerChunk
;
58 /* For yaffs2 writing there must be both data and tags.
59 * If we're using inband tags, then the tags are stuffed into
60 * the end of the data buffer.
64 else if(dev
->inbandTags
){
65 yaffs_PackedTags2TagsPart
*pt2tp
;
66 pt2tp
= (yaffs_PackedTags2TagsPart
*)(data
+ dev
->nDataBytesPerChunk
);
67 yaffs_PackTags2TagsPart(pt2tp
,tags
);
70 yaffs_PackTags2(&pt
, tags
);
72 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
73 ops
.mode
= MTD_OOB_AUTO
;
74 ops
.ooblen
= (dev
->inbandTags
) ? 0 : sizeof(pt
);
75 ops
.len
= dev
->totalBytesPerChunk
;
77 ops
.datbuf
= (__u8
*)data
;
78 ops
.oobbuf
= (dev
->inbandTags
) ? NULL
: (void *)&pt
;
79 retval
= mtd
->write_oob(mtd
, addr
, &ops
);
82 if (!dev
->inbandTags
) {
84 mtd
->write_ecc(mtd
, addr
, dev
->nDataBytesPerChunk
,
85 &dummy
, data
, (__u8
*) & pt
, NULL
);
88 mtd
->write(mtd
, addr
, dev
->totalBytesPerChunk
, &dummy
,
99 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device
* dev
, int chunkInNAND
,
100 __u8
* data
, yaffs_ExtendedTags
* tags
)
102 struct mtd_info
*mtd
= (struct mtd_info
*)(dev
->genericDevice
);
103 #if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
104 struct mtd_oob_ops ops
;
110 loff_t addr
= ((loff_t
) chunkInNAND
) * dev
->nDataBytesPerChunk
;
112 yaffs_PackedTags2 pt
;
116 ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
117 TENDSTR
), chunkInNAND
, data
, tags
));
123 data
= yaffs_GetTempBuffer(dev
,__LINE__
);
130 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
131 if (dev
->inbandTags
|| (data
&& !tags
))
132 retval
= mtd
->read(mtd
, addr
, dev
->totalBytesPerChunk
,
135 ops
.mode
= MTD_OOB_AUTO
;
136 ops
.ooblen
= sizeof(pt
);
137 ops
.len
= data
? dev
->nDataBytesPerChunk
: sizeof(pt
);
140 ops
.oobbuf
= dev
->spareBuffer
;
141 retval
= mtd
->read_oob(mtd
, addr
, &ops
);
144 if (!dev
->inbandTags
&& data
&& tags
) {
146 retval
= mtd
->read_ecc(mtd
, addr
, dev
->nDataBytesPerChunk
,
147 &dummy
, data
, dev
->spareBuffer
,
152 mtd
->read(mtd
, addr
, dev
->nDataBytesPerChunk
, &dummy
,
154 if (!dev
->inbandTags
&& tags
)
156 mtd
->read_oob(mtd
, addr
, mtd
->oobsize
, &dummy
,
164 yaffs_PackedTags2TagsPart
* pt2tp
;
165 pt2tp
= (yaffs_PackedTags2TagsPart
*)&data
[dev
->nDataBytesPerChunk
];
166 yaffs_UnpackTags2TagsPart(tags
,pt2tp
);
171 memcpy(&pt
, dev
->spareBuffer
, sizeof(pt
));
172 yaffs_UnpackTags2(tags
, &pt
);
177 yaffs_ReleaseTempBuffer(dev
,data
,__LINE__
);
179 if(tags
&& retval
== -EBADMSG
&& tags
->eccResult
== YAFFS_ECC_RESULT_NO_ERROR
)
180 tags
->eccResult
= YAFFS_ECC_RESULT_UNFIXED
;
187 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct
*dev
, int blockNo
)
189 struct mtd_info
*mtd
= (struct mtd_info
*)(dev
->genericDevice
);
192 (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR
), blockNo
));
195 mtd
->block_markbad(mtd
,
196 blockNo
* dev
->nChunksPerBlock
*
197 dev
->nDataBytesPerChunk
);
206 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct
*dev
, int blockNo
,
207 yaffs_BlockState
* state
, int *sequenceNumber
)
209 struct mtd_info
*mtd
= (struct mtd_info
*)(dev
->genericDevice
);
213 (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR
), blockNo
));
215 mtd
->block_isbad(mtd
,
216 blockNo
* dev
->nChunksPerBlock
*
217 dev
->nDataBytesPerChunk
);
220 T(YAFFS_TRACE_MTD
, (TSTR("block is bad" TENDSTR
)));
222 *state
= YAFFS_BLOCK_STATE_DEAD
;
225 yaffs_ExtendedTags t
;
226 nandmtd2_ReadChunkWithTagsFromNAND(dev
,
228 dev
->nChunksPerBlock
, NULL
,
232 *sequenceNumber
= t
.sequenceNumber
;
233 *state
= YAFFS_BLOCK_STATE_NEEDS_SCANNING
;
236 *state
= YAFFS_BLOCK_STATE_EMPTY
;
240 (TSTR("block is bad seq %d state %d" TENDSTR
), *sequenceNumber
,