Added create and validate tests.
[yaffs2.git] / yaffs_mtdif_single.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2018 Aleph One Ltd.
5  *
6  * Created by Charles Manning <charles@aleph1.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include "yportenv.h"
14
15 #include "yaffs_mtdif.h"
16
17 #include "linux/mtd/mtd.h"
18 #include "linux/types.h"
19 #include "linux/time.h"
20 #include "linux/mtd/nand.h"
21 #include "linux/kernel.h"
22 #include "linux/version.h"
23 #include "linux/types.h"
24
25 #include "yaffs_trace.h"
26 #include "yaffs_guts.h"
27 #include "yaffs_linux.h"
28
29
30 int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
31 {
32         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
33         u32 addr =
34             ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
35             dev->param.chunks_per_block;
36         struct erase_info ei;
37         int retval = 0;
38
39         ei.mtd = mtd;
40         ei.addr = addr;
41         ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
42         ei.time = 1000;
43         ei.retries = 2;
44         ei.callback = NULL;
45         ei.priv = (u_long) dev;
46
47         retval = mtd->erase(mtd, &ei);
48
49         if (retval == 0)
50                 return YAFFS_OK;
51
52         return YAFFS_FAIL;
53 }
54
55
56 static  int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
57                                    const u8 *data, int data_len,
58                                    const u8 *oob, int oob_len)
59 {
60         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
61         loff_t addr;
62         struct mtd_oob_ops ops;
63         int retval;
64
65         addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
66         memset(&ops, 0, sizeof(ops));
67         ops.mode = MTD_OPS_AUTO_OOB;
68         ops.len = (data) ? data_len : 0;
69         ops.ooblen = oob_len;
70         ops.datbuf = (u8 *)data;
71         ops.oobbuf = (u8 *)oob;
72
73         retval = mtd->write_oob(mtd, addr, &ops);
74         if (retval) {
75                 yaffs_trace(YAFFS_TRACE_MTD,
76                         "write_oob failed, chunk %d, mtd error %d",
77                         nand_chunk, retval);
78         }
79         return retval ? YAFFS_FAIL : YAFFS_OK;
80 }
81
82 static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
83                                    u8 *data, int data_len,
84                                    u8 *oob, int oob_len,
85                                    enum yaffs_ecc_result *ecc_result)
86 {
87         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
88         loff_t addr;
89         struct mtd_oob_ops ops;
90         int retval;
91
92         addr = ((loff_t) nand_chunk) * dev->data_bytes_per_chunk;
93         memset(&ops, 0, sizeof(ops));
94         ops.mode = MTD_OPS_AUTO_OOB;
95         ops.len = (data) ? data_len : 0;
96         ops.ooblen = oob_len;
97         ops.datbuf = data;
98         ops.oobbuf = oob;
99
100         /* Read page and oob using MTD.
101          * Check status and determine ECC result.
102          */
103         retval = mtd->read_oob(mtd, addr, &ops);
104         if (retval)
105                 yaffs_trace(YAFFS_TRACE_MTD,
106                         "read_oob failed, chunk %d, mtd error %d",
107                         nand_chunk, retval);
108
109         switch (retval) {
110         case 0:
111                 /* no error */
112                 if(ecc_result)
113                         *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
114                 break;
115
116         case -EUCLEAN:
117                 /* MTD's ECC fixed the data */
118                 if(ecc_result)
119                         *ecc_result = YAFFS_ECC_RESULT_FIXED;
120                 dev->n_ecc_fixed++;
121                 break;
122
123         case -EBADMSG:
124         default:
125                 /* MTD's ECC could not fix the data */
126                 dev->n_ecc_unfixed++;
127                 if(ecc_result)
128                         *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
129                 return YAFFS_FAIL;
130         }
131
132         return YAFFS_OK;
133 }
134
135 static  int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
136 {
137         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
138
139         loff_t addr;
140         struct erase_info ei;
141         int retval = 0;
142         u32 block_size;
143
144         block_size = dev->param.total_bytes_per_chunk *
145                      dev->param.chunks_per_block;
146         addr = ((loff_t) block_no) * block_size;
147
148         ei.mtd = mtd;
149         ei.addr = addr;
150         ei.len = block_size;
151         ei.time = 1000;
152         ei.retries = 2;
153         ei.callback = NULL;
154         ei.priv = (u_long) dev;
155
156         retval = mtd->erase(mtd, &ei);
157
158         if (retval == 0)
159                 return YAFFS_OK;
160
161         return YAFFS_FAIL;
162 }
163
164 static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
165 {
166         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
167         int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
168         int retval;
169
170         yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
171
172         retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
173         return (retval) ? YAFFS_FAIL : YAFFS_OK;
174 }
175
176 static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
177 {
178         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
179         int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
180         int retval;
181
182         yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "checking block %d bad", block_no);
183
184         retval = mtd->block_isbad(mtd, (loff_t) blocksize * block_no);
185         return (retval) ? YAFFS_FAIL : YAFFS_OK;
186 }
187
188 static int yaffs_mtd_initialise(struct yaffs_dev *dev)
189 {
190         return YAFFS_OK;
191 }
192
193 static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
194 {
195         return YAFFS_OK;
196 }
197
198
199
200 void yaffs_mtd_drv_install(struct yaffs_dev *dev)
201 {
202         struct yaffs_driver *drv = &dev->drv;
203
204         drv->drv_write_chunk_fn = yaffs_mtd_write;
205         drv->drv_read_chunk_fn = yaffs_mtd_read;
206         drv->drv_erase_fn = yaffs_mtd_erase;
207         drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
208         drv->drv_check_bad_fn = yaffs_mtd_check_bad;
209         drv->drv_initialise_fn = yaffs_mtd_initialise;
210         drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
211 }