Wide tnode support
[yaffs2.git] / yaffs_mtdif2.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  * yaffs_mtdif.c  NAND mtd wrapper functions.
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
6  *   for Toby Churchill Ltd and Brightstar Engineering
7  *
8  * Created by Charles Manning <charles@aleph1.co.uk>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15
16 /* mtd interface for YAFFS2 */
17
18 const char *yaffs_mtdif2_c_version =
19     "$Id: yaffs_mtdif2.c,v 1.9 2005-12-07 21:49:18 charles Exp $";
20
21 #include "yportenv.h"
22
23
24 #include "yaffs_mtdif2.h"
25
26 #include "linux/mtd/mtd.h"
27 #include "linux/types.h"
28 #include "linux/time.h"
29
30 #include "yaffs_packedtags2.h"
31
32 int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
33                                       const __u8 * data,
34                                       const yaffs_ExtendedTags * tags)
35 {
36         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
37         size_t dummy;
38         int retval = 0;
39
40         loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
41
42         yaffs_PackedTags2 pt;
43
44         T(YAFFS_TRACE_MTD,
45           (TSTR
46            ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
47             TENDSTR), chunkInNAND, data, tags));
48
49         if (tags) {
50                 yaffs_PackTags2(&pt, tags);
51         }
52
53         if (data && tags) {
54                 if (dev->useNANDECC)
55                         retval =
56                             mtd->write_ecc(mtd, addr, dev->nBytesPerChunk,
57                                            &dummy, data, (__u8 *) & pt, NULL);
58                 else
59                         retval =
60                             mtd->write_ecc(mtd, addr, dev->nBytesPerChunk,
61                                            &dummy, data, (__u8 *) & pt, NULL);
62         } else {
63                 if (data)
64                         retval =
65                             mtd->write(mtd, addr, dev->nBytesPerChunk, &dummy,
66                                        data);
67                 if (tags)
68                         retval =
69                             mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
70                                            (__u8 *) & pt);
71
72         }
73
74         if (retval == 0)
75                 return YAFFS_OK;
76         else
77                 return YAFFS_FAIL;
78 }
79
80 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
81                                        __u8 * data, yaffs_ExtendedTags * tags)
82 {
83         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
84         size_t dummy;
85         int retval = 0;
86
87         loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
88
89         yaffs_PackedTags2 pt;
90
91         T(YAFFS_TRACE_MTD,
92           (TSTR
93            ("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p"
94             TENDSTR), chunkInNAND, data, tags));
95
96         if (1 ||  /* Always do this */
97             data && tags) {
98                 if (dev->useNANDECC) {
99                         retval =
100                             mtd->read_ecc(mtd, addr, dev->nBytesPerChunk,
101                                           &dummy, data, dev->spareBuffer,
102                                           NULL);
103                 } else {
104                         retval =
105                             mtd->read_ecc(mtd, addr, dev->nBytesPerChunk,
106                                           &dummy, data, dev->spareBuffer,
107                                           NULL);
108                 }
109         } else {
110                 if (data)
111                         retval =
112                             mtd->read(mtd, addr, dev->nBytesPerChunk, &dummy,
113                                       data);
114                 if (tags)
115                         retval =
116                             mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
117                                           dev->spareBuffer);
118         }
119
120         memcpy(&pt, dev->spareBuffer, sizeof(pt));
121
122         if (tags)
123                 yaffs_UnpackTags2(tags, &pt);
124
125         if (retval == 0)
126                 return YAFFS_OK;
127         else
128                 return YAFFS_FAIL;
129 }
130
131 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
132 {
133         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
134         int retval;
135         T(YAFFS_TRACE_MTD,
136           (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
137
138         retval =
139             mtd->block_markbad(mtd,
140                                blockNo * dev->nChunksPerBlock *
141                                dev->nBytesPerChunk);
142
143         if (retval == 0)
144                 return YAFFS_OK;
145         else
146                 return YAFFS_FAIL;
147
148 }
149
150 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
151                             yaffs_BlockState * state, int *sequenceNumber)
152 {
153         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
154         int retval;
155
156         T(YAFFS_TRACE_MTD,
157           (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
158         retval =
159             mtd->block_isbad(mtd,
160                              blockNo * dev->nChunksPerBlock *
161                              dev->nBytesPerChunk);
162
163         if (retval) {
164                 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
165
166                 *state = YAFFS_BLOCK_STATE_DEAD;
167                 *sequenceNumber = 0;
168         } else {
169                 yaffs_ExtendedTags t;
170                 nandmtd2_ReadChunkWithTagsFromNAND(dev,
171                                                    blockNo *
172                                                    dev->nChunksPerBlock, NULL,
173                                                    &t);
174
175                 if (t.chunkUsed) {
176                         *sequenceNumber = t.sequenceNumber;
177                         *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
178                 } else {
179                         *sequenceNumber = 0;
180                         *state = YAFFS_BLOCK_STATE_EMPTY;
181                 }
182         }
183         T(YAFFS_TRACE_MTD,
184           (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
185            *state));
186
187         if (retval == 0)
188                 return YAFFS_OK;
189         else
190                 return YAFFS_FAIL;
191 }
192