Set up u-boot glue code and patching scripts.
[yaffs2.git] / direct / u-boot / fs / yaffs2 / yaffs_mtdif2.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
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.
12  */
13
14 /* mtd interface for YAFFS2 */
15
16 /* XXX U-BOOT XXX */
17 #include <common.h>
18 #include "asm/errno.h"
19
20 #include "yportenv.h"
21 #include "yaffs_trace.h"
22
23 #include "yaffs_mtdif2.h"
24
25 #include "linux/mtd/mtd.h"
26 #include "linux/types.h"
27 #include "linux/time.h"
28
29 #include "yaffs_trace.h"
30 #include "yaffs_packedtags2.h"
31 #include "string.h"
32
33 #define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
34 #define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
35
36
37 /* NB For use with inband tags....
38  * We assume that the data buffer is of size total_bytes_per_chunk so
39  * that we can also use it to load the tags.
40  */
41 int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
42                               const u8 *data,
43                               const struct yaffs_ext_tags *tags)
44 {
45         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
46 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
47         struct mtd_oob_ops ops;
48 #else
49         size_t dummy;
50 #endif
51         int retval = 0;
52
53         loff_t addr;
54         u8 local_spare[128];
55
56         struct yaffs_packed_tags2 pt;
57
58         int packed_tags_size =
59             dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
60         void *packed_tags_ptr =
61             dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
62
63         yaffs_trace(YAFFS_TRACE_MTD,
64                 "nandmtd2_write_chunk_tags chunk %d data %p tags %p",
65                 nand_chunk, data, tags);
66
67         addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
68
69         /* For yaffs2 writing there must be both data and tags.
70          * If we're using inband tags, then the tags are stuffed into
71          * the end of the data buffer.
72          */
73         if (!data || !tags)
74                 BUG();
75         else if (dev->param.inband_tags) {
76                 struct yaffs_packed_tags2_tags_only *pt2tp;
77                 pt2tp =
78                     (struct yaffs_packed_tags2_tags_only *)(data +
79                                                         dev->
80                                                         data_bytes_per_chunk);
81                 yaffs_pack_tags2_tags_only(pt2tp, tags);
82         } else {
83                 yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
84         }
85
86 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
87         ops.mode = MTD_OOB_AUTO;
88         ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
89         ops.len = dev->param.total_bytes_per_chunk;
90         ops.ooboffs = 0;
91         ops.datbuf = (u8 *) data;
92         ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
93         retval = mtd->write_oob(mtd, addr, &ops);
94
95 #else
96         if (!dev->param.inband_tags) {
97                 retval =
98                     mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
99                                    &dummy, data, (u8 *) packed_tags_ptr, NULL);
100         } else {
101                 retval =
102                     mtd->write(mtd, addr, dev->param.total_bytes_per_chunk,
103                                &dummy, data);
104         }
105 #endif
106
107         if (retval == 0)
108                 return YAFFS_OK;
109         else
110                 return YAFFS_FAIL;
111 }
112
113 int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
114                              u8 *data, struct yaffs_ext_tags *tags)
115 {
116         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
117
118         u8 local_spare[128];
119
120 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
121         struct mtd_oob_ops ops;
122 #endif
123         size_t dummy;
124         int retval = 0;
125         int local_data = 0;
126
127         loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
128
129         struct yaffs_packed_tags2 pt;
130
131         int packed_tags_size =
132             dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
133         void *packed_tags_ptr =
134             dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
135
136         yaffs_trace(YAFFS_TRACE_MTD,
137                 "nandmtd2_read_chunk_tags chunk %d data %p tags %p",
138                 nand_chunk, data, tags);
139
140         if (dev->param.inband_tags) {
141
142                 if (!data) {
143                         local_data = 1;
144                         data = yaffs_get_temp_buffer(dev);
145                 }
146
147         }
148
149 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
150         if (dev->param.inband_tags || (data && !tags))
151                 retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
152                                    &dummy, data);
153         else if (tags) {
154                 ops.mode = MTD_OOB_AUTO;
155                 ops.ooblen = packed_tags_size;
156                 ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
157                 ops.ooboffs = 0;
158                 ops.datbuf = data;
159                 ops.oobbuf = local_spare;
160                 retval = mtd->read_oob(mtd, addr, &ops);
161         }
162 #else
163         if (!dev->param.inband_tags && data && tags) {
164
165                 retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
166                                        &dummy, data, dev->spare_buffer, NULL);
167         } else {
168                 if (data)
169                         retval =
170                             mtd->read(mtd, addr, dev->data_bytes_per_chunk,
171                                       &dummy, data);
172                 if (!dev->param.inband_tags && tags)
173                         retval =
174                             mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
175                                           dev->spare_buffer);
176         }
177 #endif
178
179         if (dev->param.inband_tags) {
180                 if (tags) {
181                         struct yaffs_packed_tags2_tags_only *pt2tp;
182                         pt2tp =
183                                 (struct yaffs_packed_tags2_tags_only *)
184                                 &data[dev->data_bytes_per_chunk];
185                         yaffs_unpack_tags2_tags_only(tags, pt2tp);
186                 }
187         } else {
188                 if (tags) {
189                         memcpy(packed_tags_ptr,
190                                local_spare,
191                                packed_tags_size);
192                         yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
193                 }
194         }
195
196         if (local_data)
197                 yaffs_release_temp_buffer(dev, data);
198
199         if (tags && retval == -EBADMSG
200             && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
201                 tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
202                 dev->n_ecc_unfixed++;
203         }
204         if (tags && retval == -EUCLEAN
205             && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
206                 tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
207                 dev->n_ecc_fixed++;
208         }
209         if (retval == 0)
210                 return YAFFS_OK;
211         else
212                 return YAFFS_FAIL;
213 }
214
215
216 int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo)
217 {
218         struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
219         int retval;
220
221         yaffs_trace(YAFFS_TRACE_MTD,
222                 "nandmtd2_MarkNANDBlockBad %d", blockNo);
223
224         retval =
225             mtd->block_markbad(mtd,
226                                blockNo * dev->param.chunks_per_block *
227                                dev->data_bytes_per_chunk);
228
229         if (retval == 0)
230                 return YAFFS_OK;
231         else
232                 return YAFFS_FAIL;
233
234 }
235
236 int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
237                             enum yaffs_block_state * state, u32 *sequenceNumber)
238 {
239         struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
240         int retval;
241
242         yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo);
243         retval =
244             mtd->block_isbad(mtd,
245                              blockNo * dev->param.chunks_per_block *
246                              dev->data_bytes_per_chunk);
247
248         if (retval) {
249                 yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
250
251                 *state = YAFFS_BLOCK_STATE_DEAD;
252                 *sequenceNumber = 0;
253         } else {
254                 struct yaffs_ext_tags t;
255                 nandmtd2_read_chunk_tags(dev,
256                                                    blockNo *
257                                                    dev->param.chunks_per_block, NULL,
258                                                    &t);
259
260                 if (t.chunk_used) {
261                         *sequenceNumber = t.seq_number;
262                         *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
263                 } else {
264                         *sequenceNumber = 0;
265                         *state = YAFFS_BLOCK_STATE_EMPTY;
266                 }
267         }
268         yaffs_trace(YAFFS_TRACE_MTD, "block is bad seq %d state %d", *sequenceNumber, *state);
269
270         if (retval == 0)
271                 return YAFFS_OK;
272         else
273                 return YAFFS_FAIL;
274 }