linux/drivers/mtd/inftlcore.c
<<
0" /spaion /formon a 0" href="../linux+v3.9.1/drivers/mtd/inftlcore.c">0" img src="../.static/gfx/right.png" alt=">>">0" /spaion0" spai class="lxr_search">0" 0" input typluehidden" namluenavtarget" n value">0" input typluetext" namluesearch" iduesearch">0" butttiotypluesubmit">Search0" Prefsn /a>0" /spaion /divon form acopti="ajax+*" method="post" onsubmit="return false;">0" input typluehidden" namlueajax_lookup" idueajax_lookup" n value">0 /formon0 div class="headingbotttm">n div iduefile_contents"o
 
1 /a> spai class="comment">/* /spaion
 
2 /a> spai class="comment"> * inftlcore.c -- Linux driver for Inverse Flash TranslaoptioLayer (INFTL) /spaion
 
3 /a> spai class="comment"> * /spaion
 
4 /a> spai class="comment"> * Copyright © 2002, Greg Ungerer (gerg@snapgear.com) /spaion
 
5 /a> spai class="comment"> * /spaion
 
6 /a> spai class="comment"> * Based heavily tiothe nftlcore.c code which is: /spaion
 
7 /a> spai class="comment"> * Copyright © 1999 Machine VisptioHoldings, Inc. /spaion
 
8 /a> spai class="comment"> * Copyright © 1999 David Woodhouse <dwmw2@infradead.org> /spaion
 
9 /a> spai class="comment"> * /spaion
 8.10a> spai class="comment"> * This program is free software; you cai redistribute it and/or modify /spaion
 11 /a> spai class="comment"> * it under the terms of the GNU General Public License as published by /spaion
 12 /a> spai class="comment"> * the Free Software Foundaopti; either versptio2 of the License, or /spaion
 13 /a> spai class="comment"> * (at your 
 14 /a> spai class="comment"> * /spaion
 15 /a> spai class="comment"> * This program is distributed in the hope that it will be useful, /spaion
 16 /a> spai class="comment"> * but WITHOUT ANY WARRANTY; without even the implied warranty tf /spaion
 17 /a> spai class="comment"> * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the /spaion
 18 /a> spai class="comment"> * GNU General Public License for more details. /spaion
 19 /a> spai class="comment"> * /spaion
 2.10a> spai class="comment"> * You should have received a copy of the GNU General Public License /spaion
 21 /a> spai class="comment"> * along with this program; if not, write to the Free Software /spaion
 22 /a> spai class="comment"> * Foundaopti, Inc., 59 Temple Place, Suite 330, Bostti, MA  02111-1307  USA /spaion
 23 /a> spai class="comment"> */ /spaion
 24 /a>n
 25 /a>#include <linux/kernel.h /a>>n
 26 /a>#include <linux/module.h /a>>n
 27 /a>#include <linux/delay.h /a>>n
 28 /a>#include <linux/slab.h /a>>n
 29 /a>#include <linux/sched.h /a>>n
 30 /a>#include <linux/init.h /a>>n
 31 /a>#include <linux/kmod.h /a>>n
 32 /a>#include <linux/hdreg.h /a>>n
 33 /a>#include <linux/mtd/mtd.h /a>>n
 34 /a>#include <linux/mtd/nftl.h /a>>n
 35 /a>#include <linux/mtd/inftl.h /a>>n
 36 /a>#include <linux/mtd/nand.h /a>>n
 37 /a>#include <asm/uaccess.h /a>>n
 38 /a>#include <asm/errno.h /a>>n
 39 /a>#include <asm/io.h /a>>n
 40 /a>n
 41 /a> spai class="comment">/* /spaion
 42 /a> spai class="comment"> * Maximum number of loops while examining next block, to have a /spaion
 43 /a> spai class="comment"> * chance to detect consistency problems (they should never happen /spaion
 44 /a> spai class="comment"> * because of the checks done in the mounting. /spaion
 45 /a> spai class="comment"> */ /spaion
 46 /a>#define MAX_LOOPS /a> 10000n
 47 /a>n
 48 /a>static void inftl_add_mtd /a>(struct mtd_blktrans_ops /a> *tr /a>, struct mtd_info /a> *mtd /a>)n
 49 /a>{n
 50 /a>        struct INFTLrecord /a> *inftl /a>;n
 51 /a>        unsigned long temp /a>;n
 52 /a>n
 53 /a>        if (mtd /a>-> a href="+code=type" class="sref">type /a> != MTD_NANDFLASH /a> || mtd /a>-> a href="+code=size" class="sref">size /a> > UINT_MAX /a>)n
 54 /a>                return;n
 55 /a>         spai class="comment">/* OK, this is moderately ugly.  But probably safe.  Alternatives? */ /spaion
 56 /a>        if (memcmp /a>(mtd /a>-> a href="+code=naml" class="sref">naml /a>,  spai class="string">"DiskOnChip" /spaio, 10))n
 57 /a>                return;n
 58 /a>n
 59 /a>        if (!mtd /a>-> a href="+code=_block_isbad" class="sref">_block_isbad /a>) {n
 60 /a>                 a href="+code=printk" class="sref">printk /a>(KERN_ERR /a>n
 61 /a> spai class="string">"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n" /spaion
 62 /a> spai class="string">"Please useothe new diskonchip driver under the NAND subsystem.\n" /spaio);n
 63 /a>                return;n
 64 /a>        }n
 65 /a>n
 66 /a>         a href="+code=pr_debug" class="sref">pr_debug /a>("INFTL: add_mtd for %s\n" /spaio, mtd /a>-> a href="+code=naml" class="sref">naml /a>);n
 67 /a>n
 68 /a>         a href="+code=inftl" class="sref">inftl /a> = kzalloc /a>(sizeof(*inftl /a>), GFP_KERNEL /a>);n
 69 /a>n
 70 /a>        if (!inftl /a>)n
 71 /a>                return;n
 72 /a>n
 73 /a>         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.mtd /a> = mtd /a>;n
 74 /a>         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.devnum /a> = -1;n
 75 /a>n
 76 /a>         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.tr /a> = tr /a>;n
 77 /a>n
 78 /a>        if (INFTL_mount /a>(inftl /a>) < 0) {n
 79 /a>                 a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: could not mount device\n" /spaio);n
 80 /a>                 a href="+code=kfree" class="sref">kfree /a>(inftl /a>);n
 81 /a>                return;n
 82 /a>        }n
 83 /a>n
 84 /a>         spai class="comment">/* OK, it's a new one. Set up all the data structures. */ /spaion
 85 /a>n
 86 /a>         spai class="comment">/* Calculaoe geometry */ /spaion
 87 /a>         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=cylinders" class="sref">cylinders /a> = 1024;n
 88 /a>         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=heads" class="sref">heads /a> = 16;n
 89 /a>n
 90 /a>         a href="+code=temp" class="sref">temp /a> = inftl /a>-> a href="+code=cylinders" class="sref">cylinders /a> *  a href="+code=inftl" class="sref">inftl /a>-> a href="+code=heads" class="sref">heads /a>;n
 91 /a>         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=sectors" class="sref">sectors /a> = inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.size /a> / temp /a>;n
 92 /a>        if (inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.size /a> % temp /a>) {n
 93 /a>                 a href="+code=inftl" class="sref">inftl /a>-> a href="+code=sectors" class="sref">sectors /a>++;n
 94 /a>                 a href="+code=temp" class="sref">temp /a> = inftl /a>-> a href="+code=cylinders" class="sref">cylinders /a> *  a href="+code=inftl" class="sref">inftl /a>-> a href="+code=sectors" class="sref">sectors /a>;n
 95 /a>                 a href="+code=inftl" class="sref">inftl /a>-> a href="+code=heads" class="sref">heads /a> = inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.size /a> / temp /a>;n
 96 /a>n
 97 /a>                if (inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.size /a> % temp /a>) {n
 98 /a>                         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=heads" class="sref">heads /a>++;n
 99 /a>                         a href="+code=temp" class="sref">temp /a> = inftl /a>-> a href="+code=heads" class="sref">heads /a> *  a href="+code=inftl" class="sref">inftl /a>-> a href="+code=sectors" class="sref">sectors /a>;n
100 /a>                         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=cylinders" class="sref">cylinders /a> = inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.size /a> / temp /a>;n
101 /a>                }n
102 /a>        }n
103 /a>n
104 /a>        if (inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.size /a> != inftl /a>-> a href="+code=heads" class="sref">heads /a> *  a href="+code=inftl" class="sref">inftl /a>-> a href="+code=cylinders" class="sref">cylinders /a> *  a href="+code=inftl" class="sref">inftl /a>-> a href="+code=sectors" class="sref">sectors /a>) {n
105 /a>                 spai class="comment">/* /spaion
106 /a> spai class="comment">                  Oh no we don't have /spaion
107 /a> spai class="comment">                   mbd.size == heads * cylinders * sectors /spaion
108 /a> spai class="comment">                */ /spaion
109 /a>                 a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: cannot calculaoe a geometry to " /spaion
110 /a>                       "match size of 0x%lx.\n" /spaio, inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.size /a>);n
111 /a>                 a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: using C:%d H:%d S:%d " /spaion
112 /a>                        "(== 0x%lx sects)\n" /spaio,n
113 /a>                         a href="+code=inftl" class="sref">inftl /a>-> a href="+code=cylinders" class="sref">cylinders /a>, inftl /a>-> a href="+code=heads" class="sref">heads /a> , inftl /a>-> a href="+code=sectors" class="sref">sectors /a>,n
114 /a>                        (long) a href="+code=inftl" class="sref">inftl /a>-> a href="+code=cylinders" class="sref">cylinders /a> * (long) a href="+code=inftl" class="sref">inftl /a>-> a href="+code=heads" class="sref">heads /a> *n
115 /a>                        (long) a href="+code=inftl" class="sref">inftl /a>-> a href="+code=sectors" class="sref">sectors /a> );n
116 /a>        }n
117 /a>n
118 /a>        if (add_mtd_blktrans_dev /a>(& a href="+code=inftl" class="sref">inftl /a>-> a href="+code=mbd" class="sref">mbd /a>)) {n
119 /a>                 a href="+code=kfree" class="sref">kfree /a>(inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>);n
120 /a>                 a href="+code=kfree" class="sref">kfree /a>(inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>);n
121 /a>                 a href="+code=kfree" class="sref">kfree /a>(inftl /a>);n
122 /a>                return;n
123 /a>        }n
124 /a>#ifdef  a href="+code=PSYCHO_DEBUG" class="sref">PSYCHO_DEBUG /a>n
125 /a>         a href="+code=printk" class="sref">printk /a>(KERN_INFO /a> "INFTL: Found new inftl%c\n" /spaio, inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.devnum /a> + 'a' /spaio);n
126 /a>#endifn
127 /a>        return;n
128 /a>}n
129 /a>n
130 /a>static void inftl_remove_dev /a>(struct mtd_blktrans_dev /a> *dev /a>)n
131 /a>{n
132 /a>        struct INFTLrecord /a> *inftl /a> = (void *) a href="+code=dev" class="sref">dev /a>;n
133 /a>n
134 /a>         a href="+code=pr_debug" class="sref">pr_debug /a>("INFTL: remove_dev (i=%d)\n" /spaio,  a href="+code=dev" class="sref">dev /a>-> a href="+code=devnum" class="sref">devnum /a>);n
135 /a>n
136 /a>         a href="+code=del_mtd_blktrans_dev" class="sref">del_mtd_blktrans_dev /a>(dev /a>);n
137 /a>n
138 /a>         a href="+code=kfree" class="sref">kfree /a>(inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>);n
139 /a>         a href="+code=kfree" class="sref">kfree /a>(inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>);n
140 /a>}n
141 /a>n
142 /a> spai class="comment">/* /spaion
143 /a> spai class="comment"> * Actual INFTL access routines. /spaion
144 /a> spai class="comment"> */ /spaion
145 /a>n
146 /a> spai class="comment">/* /spaion
147 /a> spai class="comment"> * Read oob data from flash /spaion
148 /a> spai class="comment"> */ /spaion
149 /a>int inftl_read_oob /a>(struct mtd_info /a> *mtd /a>,  a href="+code=loff_t" class="sref">loff_t /a> offs /a>,  a href="+code=size_t" class="sref">size_t /a> len /a>,n
150 /a>                    a href="+code=size_t" class="sref">size_t /a> *retlen /a>,  a href="+code=uint8_t" class="sref">uint8_t /a> *buf /a>)n
151 /a>{n
152 /a>        struct mtd_oob_ops /a> ops /a>;n
153 /a>        int res /a>;n
154 /a>n
155 /a>         a href="+code=ops" class="sref">ops /a>.mode /a> = MTD_OPS_PLACE_OOB /a>;n
156 /a>         a href="+code=ops" class="sref">ops /a>.ooboffs /a> = offs /a> & (mtd /a>-> a href="+code=writesize" class="sref">writesize /a> - 1);n
157 /a>         a href="+code=ops" class="sref">ops /a>.ooblen /a> = len /a>;n
158 /a>         a href="+code=ops" class="sref">ops /a>.oobbuf /a> = buf /a>;n
159 /a>         a href="+code=ops" class="sref">ops /a>.datbuf /a> = NULL /a>;n
160 /a>n
161 /a>         a href="+code=res" class="sref">res /a> = mtd_read_oob /a>(mtd /a>,  a href="+code=offs" class="sref">offs /a> & ~(mtd /a>-> a href="+code=writesize" class="sref">writesize /a> - 1), & a href="+code=ops" class="sref">ops /a>);n
162 /a>        *retlen /a> = ops /a>.oobretlen /a>;n
163 /a>        return res /a>;n
164 /a>}n
165 /a>n
166 /a> spai class="comment">/* /spaion
167 /a> spai class="comment"> * Write oob data to flash /spaion
168 /a> spai class="comment"> */ /spaion
169 /a>int inftl_write_oob /a>(struct mtd_info /a> *mtd /a>,  a href="+code=loff_t" class="sref">loff_t /a> offs /a>,  a href="+code=size_t" class="sref">size_t /a> len /a>,n
170 /a>                     a href="+code=size_t" class="sref">size_t /a> *retlen /a>,  a href="+code=uint8_t" class="sref">uint8_t /a> *buf /a>)n
171 /a>{n
172 /a>        struct mtd_oob_ops /a> ops /a>;n
173 /a>        int res /a>;n
174 /a>n
175 /a>         a href="+code=ops" class="sref">ops /a>.mode /a> = MTD_OPS_PLACE_OOB /a>;n
176 /a>         a href="+code=ops" class="sref">ops /a>.ooboffs /a> = offs /a> & (mtd /a>-> a href="+code=writesize" class="sref">writesize /a> - 1);n
177 /a>         a href="+code=ops" class="sref">ops /a>.ooblen /a> = len /a>;n
178 /a>         a href="+code=ops" class="sref">ops /a>.oobbuf /a> = buf /a>;n
179 /a>         a href="+code=ops" class="sref">ops /a>.datbuf /a> = NULL /a>;n
180 /a>n
181 /a>         a href="+code=res" class="sref">res /a> = mtd_write_oob /a>(mtd /a>,  a href="+code=offs" class="sref">offs /a> & ~(mtd /a>-> a href="+code=writesize" class="sref">writesize /a> - 1), & a href="+code=ops" class="sref">ops /a>);n
182 /a>        *retlen /a> = ops /a>.oobretlen /a>;n
183 /a>        return res /a>;n
184 /a>}n
185 /a>n
186 /a> spai class="comment">/* /spaion
187 /a> spai class="comment"> * Write data and oob to flash /spaion
188 /a> spai class="comment"> */ /spaion
189 /a>static int inftl_write /a>(struct mtd_info /a> *mtd /a>,  a href="+code=loff_t" class="sref">loff_t /a> offs /a>,  a href="+code=size_t" class="sref">size_t /a> len /a>,n
190 /a>                       size_t /a> *retlen /a>,  a href="+code=uint8_t" class="sref">uint8_t /a> *buf /a>,  a href="+code=uint8_t" class="sref">uint8_t /a> *oob /a>)n
191 /a>{n
192 /a>        struct mtd_oob_ops /a> ops /a>;n
193 /a>        int res /a>;n
194 /a>n
195 /a>         a href="+code=ops" class="sref">ops /a>.mode /a> = MTD_OPS_PLACE_OOB /a>;n
196 /a>         a href="+code=ops" class="sref">ops /a>.ooboffs /a> = offs /a>;n
197 /a>         a href="+code=ops" class="sref">ops /a>.ooblen /a> = mtd /a>-> a href="+code=oobsize" class="sref">oobsize /a>;n
198 /a>         a href="+code=ops" class="sref">ops /a>.oobbuf /a> = oob /a>;n
199 /a>         a href="+code=ops" class="sref">ops /a>.datbuf /a> = buf /a>;n
200 /a>         a href="+code=ops" class="sref">ops /a>.len /a> = len /a>;n
201 /a>n
202 /a>         a href="+code=res" class="sref">res /a> = mtd_write_oob /a>(mtd /a>,  a href="+code=offs" class="sref">offs /a> & ~(mtd /a>-> a href="+code=writesize" class="sref">writesize /a> - 1), & a href="+code=ops" class="sref">ops /a>);n
203 /a>        *retlen /a> = ops /a>.retlen /a>;n
204 /a>        return res /a>;n
205 /a>}n
206 /a>n
207 /a> spai class="comment">/* /spaion
208 /a> spai class="comment"> * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition. /spaion
209 /a> spai class="comment"> *      This function is used when the give Virtual Unit Chain. /spaion
210 /a> spai class="comment"> */ /spaion
211 /a>static  a href="+code=u16" class="sref">u16 /a>  a href="+code=INFTL_findfreeblock" class="sref">INFTL_findfreeblock /a>(struct INFTLrecord /a> *inftl /a>, int desperate /a>)n
212 /a>{n
213 /a>         a href="+code=u16" class="sref">u16 /a>  a href="+code=pot" class="sref">pot /a> = inftl /a>-> a href="+code=LastFreeEUN" class="sref">LastFreeEUN /a>;n
214 /a>        int silly /a> = inftl /a>-> a href="+code=nb_blocks" class="sref">nb_blocks /a>;n
215 /a>n
216 /a>         a href="+code=pr_debug" class="sref">pr_debug /a>("INFTL: INFTL_findfreeblock(inftl=%p,desperate=%d)\n" /spaio,n
217 /a>                         a href="+code=inftl" class="sref">inftl /a>, desperate /a>);n
218 /a>n
219 /a>         spai class="comment">/* /spaion
220 /a> spai class="comment">         * Normally, we force a fold to happen before we run out of free /spaion
221 /a> spai class="comment">         * blocks completely. /spaion
222 /a> spai class="comment">         */ /spaion
223 /a>        if (!desperate /a> && inftl /a>-> a href="+code=numfreeEUNs" class="sref">numfreeEUNs /a> < 2) {n
224 /a>                 a href="+code=pr_debug" class="sref">pr_debug /a>("INFTL: there are too few free EUNs (%d)\n" /spaio,n
225 /a>                                 a href="+code=inftl" class="sref">inftl /a>-> a href="+code=numfreeEUNs" class="sref">numfreeEUNs /a>);n
226 /a>                return BLOCK_NIL /a>;n
227 /a>        }n
228 /a>n
229 /a>         spai class="comment">/* Scai for a free block */ /spaion
230 /a>        do {n
231 /a>                if (inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=pot" class="sref">pot /a>] == BLOCK_FREE /a>) {n
232 /a>                        inftl /a>-> a href="+code=LastFreeEUN" class="sref">LastFreeEUN /a> = pot /a>;n
233 /a>                        return pot /a>;n
234 /a>                }n
235 /a>n
236 /a>                if (++ a href="+code=pot" class="sref">pot /a> > inftl /a>-> a href="+code=lastEUN" class="sref">lastEUN /a>)n
237 /a>                         a href="+code=pot" class="sref">pot /a> = 0;n
238 /a>n
239 /a>                if (!silly /a>--) {n
240 /a>                         a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: no free blocks found!  " /spaion
241 /a>                                 spai class="string">"EUN range = %d - %d\n" /spaio, 0, inftl /a>-> a href="+code=LastFreeEUN" class="sref">LastFreeEUN /a>);n
242 /a>                        return BLOCK_NIL /a>;n
243 /a>                }n
244 /a>        } while (pot /a> != inftl /a>-> a href="+code=LastFreeEUN" class="sref">LastFreeEUN /a>);n
245 /a>n
246 /a>        return BLOCK_NIL /a>;n
247 /a>}n
248 /a>n
249 /a>static  a href="+code=u16" class="sref">u16 /a>  a href="+code=INFTL_foldchain" class="sref">INFTL_foldchain /a>(struct INFTLrecord /a> *inftl /a>, unsigned thisVUC /a>, unsigned pendingblock /a>)n
250 /a>{n
251 /a>         a href="+code=u16" class="sref">u16 /a>  a href="+code=BlockMap" class="sref">BlockMap /a>[ a href="+code=MAX_SECTORS_PER_UNIT" class="sref">MAX_SECTORS_PER_UNIT /a>];n
252 /a>        unsigned char  a href="+code=BlockDeleted" class="sref">BlockDeleted /a>[ a href="+code=MAX_SECTORS_PER_UNIT" class="sref">MAX_SECTORS_PER_UNIT /a>];n
253 /a>        unsigned int thisEUN /a>, prevEUN /a>, status /a>;n
254 /a>        struct mtd_info /a> *mtd /a> = inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.mtd /a>;n
255 /a>        int block /a>,  a href="+code=silly" class="sref">silly /a>;n
256 /a>        unsigned int targetEUN /a>;n
257 /a>        struct inftl_oob /a> oob /a>;n
258 /a>         a href="+code=size_t" class="sref">size_t /a> retlen /a>;n
259 /a>n
260 /a>         a href="+code=pr_debug" class="sref">pr_debug /a>("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,pending=%d)\n" /spaio,n
261 /a>                         a href="+code=inftl" class="sref">inftl /a>, thisVUC /a>, pendingblock /a>);n
262 /a>n
263 /a>         a href="+code=memset" class="sref">memset /a>(BlockMap /a>, 0xff, sizeof(BlockMap /a>));n
264 /a>         a href="+code=memset" class="sref">memset /a>(BlockDeleted /a>, 0, sizeof(BlockDeleted /a>));n
265 /a>n
266 /a>         a href="+code=thisEUN" class="sref">thisEUN /a> = targetEUN /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>];n
267 /a>n
268 /a>        if (thisEUN /a> == BLOCK_NIL /a>) {n
269 /a>                 a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: trying to fold non-existent " /spaion
270 /a>                        spai class="string">"Virtual Unit Chain %d!\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
271 /a>                return BLOCK_NIL /a>;n
272 /a>        }n
273 /a>n
274 /a>         spai class="comment">/* /spaion
275 /a> spai class="comment">         * Scai to find the Erase Unit which holds the actual data for each /spaion
276 /a> spai class="comment">         * 512-byte block within the Chain. /spaion
277 /a> spai class="comment">         */ /spaion
278 /a>         a href="+code=silly" class="sref">silly /a> = MAX_LOOPS /a>;n
279 /a>        while (thisEUN /a> < inftl /a>-> a href="+code=nb_blocks" class="sref">nb_blocks /a>) {n
280 /a>                for (block /a> = 0; block /a> < inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>/ a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a>; block /a> ++) {n
281 /a>                        if ((BlockMap /a>[ a href="+code=block" class="sref">block /a>] != BLOCK_NIL /a>) ||n
282 /a>                             a href="+code=BlockDeleted" class="sref">BlockDeleted /a>[ a href="+code=block" class="sref">block /a>])n
283 /a>                                continue;n
284 /a>n
285 /a>                        if (inftl_read_oob /a>(mtd /a>, (thisEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>)n
286 /a>                                           + (block /a> * SECTORSIZE /a>), 16, & a href="+code=retlen" class="sref">retlen /a>,n
287 /a>                                           (char *)& a href="+code=oob" class="sref">oob /a>) < 0)n
288 /a>                                status /a> = SECTOR_IGNORE /a>;n
289 /a>                        elsen
290 /a>                                status /a> = oob /a>.b /a>.Status /a> | oob /a>.b /a>.Status1 /a>;n
291 /a>n
292 /a>                        switch(status /a>) {n
293 /a>                        case SECTOR_FREE /a>:n
294 /a>                        case SECTOR_IGNORE /a>:n
295 /a>                                break;n
296 /a>                        case SECTOR_USED /a>:n
297 /a>                                BlockMap /a>[ a href="+code=block" class="sref">block /a>] = thisEUN /a>;n
298 /a>                                continue;n
299 /a>                        case SECTOR_DELETED /a>:n
300 /a>                                BlockDeleted /a>[ a href="+code=block" class="sref">block /a>] = 1;n
301 /a>                                continue;n
302 /a>                        default:n
303 /a>                                 a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: unknown status " /spaion
304 /a>                                         spai class="string">"for block %d in EUN %d: %x\n" /spaio,n
305 /a>                                         a href="+code=block" class="sref">block /a>,  a href="+code=thisEUN" class="sref">thisEUN /a>, status /a>);n
306 /a>                                break;n
307 /a>                        }n
308 /a>                }n
309 /a>n
310 /a>                if (!silly /a>--) {n
311 /a>                         a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: infinite loop in Virtual " /spaion
312 /a>                                 spai class="string">"Unit Chain 0x%x\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
313 /a>                        return BLOCK_NIL /a>;n
314 /a>                }n
315 /a>n
316 /a>                 a href="+code=thisEUN" class="sref">thisEUN /a> = inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>];n
317 /a>        }n
318 /a>n
319 /a>         spai class="comment">/* /spaion
320 /a> spai class="comment">         * OK. We now know the location of every block in the Virtual Unit /spaion
321 /a> spai class="comment">         * Chain, and the Erase Unit into which we are supposed to be copying. /spaion
322 /a> spai class="comment">         * Go for it. /spaion
323 /a> spai class="comment">         */ /spaion
324 /a>         a href="+code=pr_debug" class="sref">pr_debug /a>("INFTL: folding chain %d into unit %d\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>,  a href="+code=targetEUN" class="sref">targetEUN /a>);n
325 /a>n
326 /a>        for (block /a> = 0; block /a> < inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>/ a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a> ; block /a>++) {n
327 /a>                unsigned char  a href="+code=movebuf" class="sref">movebuf /a>[ a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a>];n
328 /a>                int ret /a>;n
329 /a>n
330 /a>                 spai class="comment">/* /spaion
331 /a> spai class="comment">                 * If it's in the target EUN already, or if it's pending write, /spaion
332 /a> spai class="comment">                 * do nothing. /spaion
333 /a> spai class="comment">                 */ /spaion
334 /a>                if (BlockMap /a>[ a href="+code=block" class="sref">block /a>] == targetEUN /a> || (pendingblock /a> ==n
335 /a>                    (thisVUC /a> * (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> / SECTORSIZE /a>) + block /a>))) {n
336 /a>                        continue;n
337 /a>                }n
338 /a>n
339 /a>                 spai class="comment">/* /spaion
340 /a> spai class="comment">                 * Copy only in non free block (free blocks cai only /spaion
341 /a> spai class="comment">                 * happen in case of media errors or deleted blocks). /spaion
342 /a> spai class="comment">                 */ /spaion
343 /a>                if (BlockMap /a>[ a href="+code=block" class="sref">block /a>] == BLOCK_NIL /a>)n
344 /a>                        continue;n
345 /a>n
346 /a>                 a href="+code=ret" class="sref">ret /a> = mtd_read /a>(mtd /a>,n
347 /a>                               (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> * BlockMap /a>[ a href="+code=block" class="sref">block /a>]) + (block /a> * SECTORSIZE /a>),n
348 /a>                               SECTORSIZE /a>,n
349 /a>                               & a href="+code=retlen" class="sref">retlen /a>,n
350 /a>                                a href="+code=movebuf" class="sref">movebuf /a>);n
351 /a>                if (ret /a> < 0 && !mtd_is_bitflip /a>(ret /a>)) {n
352 /a>                        ret /a> = mtd_read /a>(mtd /a>,n
353 /a>                                       (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> * BlockMap /a>[ a href="+code=block" class="sref">block /a>]) + (block /a> * SECTORSIZE /a>),n
354 /a>                                       SECTORSIZE /a>,n
355 /a>                                       & a href="+code=retlen" class="sref">retlen /a>,n
356 /a>                                        a href="+code=movebuf" class="sref">movebuf /a>);n
357 /a>                        if (ret /a> != - a href="+code=EIO" class="sref">EIO /a>)n
358 /a>                                pr_debug /a>("INFTL: error went away on retry?\n" /spaio);n
359 /a>                }n
360 /a>                 a href="+code=memset" class="sref">memset /a>(& a href="+code=oob" class="sref">oob /a>, 0xff, sizeof(struct inftl_oob /a>));n
361 /a>                 a href="+code=oob" class="sref">oob /a>.b /a>.Status /a> = oob /a>.b /a>.Status1 /a> = SECTOR_USED /a>;n
362 /a>n
363 /a>                inftl_write /a>(inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.mtd /a>, (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> * targetEUN /a>) +n
364 /a>                            (block /a> * SECTORSIZE /a>), SECTORSIZE /a>, & a href="+code=retlen" class="sref">retlen /a>,n
365 /a>                             a href="+code=movebuf" class="sref">movebuf /a>, (char *)& a href="+code=oob" class="sref">oob /a>);n
366 /a>        }n
367 /a>n
368 /a>         spai class="comment">/* /spaion
369 /a> spai class="comment">         * Newest unit in chain now contains data from _all_ older units. /spaion
370 /a> spai class="comment">         * So go through and erase each unit in chain, oldest first. (This /spaion
371 /a> spai class="comment">         * is important, by doing oldest first if we crash/reboot then it /spaion
372 /a> spai class="comment">         * it is relatively simple to cleai up the mess). /spaion
373 /a> spai class="comment">         */ /spaion
374 /a>         a href="+code=pr_debug" class="sref">pr_debug /a>("INFTL: want to erase virtual chain %d\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
375 /a>n
376 /a>        for (;;) {n
377 /a>                 spai class="comment">/* Find oldest unit in chain. */ /spaion
378 /a>                 a href="+code=thisEUN" class="sref">thisEUN /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>];n
379 /a>                 a href="+code=prevEUN" class="sref">prevEUN /a> = BLOCK_NIL /a>;n
380 /a>                while (inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>] != BLOCK_NIL /a>) {n
381 /a>                         a href="+code=prevEUN" class="sref">prevEUN /a> = thisEUN /a>;n
382 /a>                         a href="+code=thisEUN" class="sref">thisEUN /a> = inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>];n
383 /a>                }n
384 /a>n
385 /a>                 spai class="comment">/* Check if we are all done */ /spaion
386 /a>                if (thisEUN /a> == targetEUN /a>)n
387 /a>                        break;n
388 /a>n
389 /a>                 spai class="comment">/* Unlink the last block from the chain. */ /spaion
390 /a>                inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=prevEUN" class="sref">prevEUN /a>] = BLOCK_NIL /a>;n
391 /a>n
392 /a>                 spai class="comment">/* Now try to erase it. */ /spaion
393 /a>                if (INFTL_formatblock /a>(inftl /a>,  a href="+code=thisEUN" class="sref">thisEUN /a>) < 0) {n
394 /a>                         spai class="comment">/* /spaion
395 /a> spai class="comment">                         * Could not erase : mark block as reserved. /spaion
396 /a> spai class="comment">                         */ /spaion
397 /a>                        inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>] = BLOCK_RESERVED /a>;n
398 /a>                } else {n
399 /a>                         spai class="comment">/* Correctly erased : mark it as free */ /spaion
400 /a>                        inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>] = BLOCK_FREE /a>;n
401 /a>                        inftl /a>-> a href="+code=numfreeEUNs" class="sref">numfreeEUNs /a>++;n
402 /a>                }n
403 /a>        }n
404 /a>n
405 /a>        return targetEUN /a>;n
406 /a>}n
407 /a>n
408 /a>static  a href="+code=u16" class="sref">u16 /a>  a href="+code=INFTL_makefreeblock" class="sref">INFTL_makefreeblock /a>(struct INFTLrecord /a> *inftl /a>, unsigned pendingblock /a>)n
409 /a>{n
410 /a>         spai class="comment">/* /spaion
411 /a> spai class="comment">         * This is the part that needs some cleverness applied. /spaion
412 /a> spai class="comment">         * For now, I'm doing the minimum applicable to actually /spaion
413 /a> spai class="comment">         * get the thing to work. /spaion
414 /a> spai class="comment">         * Wear-levelling and other clever stuff needs to be implemented /spaion
415 /a> spai class="comment">         * and we also need to do some assessment of the results when /spaion
416 /a> spai class="comment">         * the system loses power half-way through the routine. /spaion
417 /a> spai class="comment">         */ /spaion
418 /a>         a href="+code=u16" class="sref">u16 /a>  a href="+code=LongestChain" class="sref">LongestChain /a> = 0;n
419 /a>         a href="+code=u16" class="sref">u16 /a>  a href="+code=ChainLength" class="sref">ChainLength /a> = 0,  a href="+code=thislen" class="sref">thislen /a>;n
420 /a>         a href="+code=u16" class="sref">u16 /a>  a href="+code=chain" class="sref">chain /a>,  a href="+code=EUN" class="sref">EUN /a>;n
421 /a>n
422 /a>         a href="+code=pr_debug" class="sref">pr_debug /a>("INFTL: INFTL_makefreeblock(inftl=%p," /spaion
423 /a>                "pending=%d)\n" /spaio,  a href="+code=inftl" class="sref">inftl /a>, pendingblock /a>);n
424 /a>n
425 /a>        for (chain /a> = 0; chain /a> < inftl /a>-> a href="+code=nb_blocks" class="sref">nb_blocks /a>; chain /a>++) {n
426 /a>                 a href="+code=EUN" class="sref">EUN /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=chain" class="sref">chain /a>];n
427 /a>                 a href="+code=thislen" class="sref">thislen /a> = 0;n
428 /a>n
429 /a>                while (EUN /a> <= inftl /a>-> a href="+code=lastEUN" class="sref">lastEUN /a>) {n
430 /a>                         a href="+code=thislen" class="sref">thislen /a>++;n
431 /a>                        EUN /a> = inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=EUN" class="sref">EUN /a>];n
432 /a>                        if (thislen /a> > 0xff00) {n
433 /a>                                 a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: endless loop in " /spaion
434 /a>                                         spai class="string">"Virtual Chain %d: Unit %x\n" /spaio,n
435 /a>                                         a href="+code=chain" class="sref">chain /a>,  a href="+code=EUN" class="sref">EUN /a>);n
436 /a>                                 spai class="comment">/* /spaion
437 /a> spai class="comment">                                 * Actually, don't return failure. /spaion
438 /a> spai class="comment">                                 * Just ignore this chain and get on with it. /spaion
439 /a> spai class="comment">                                 */ /spaion
440 /a>                                thislen /a> = 0;n
441 /a>                                break;n
442 /a>                        }n
443 /a>                }n
444 /a>n
445 /a>                if (thislen /a> >  a href="+code=ChainLength" class="sref">ChainLength /a>) {n
446 /a>                        ChainLength /a> =  a href="+code=thislen" class="sref">thislen /a>;n
447 /a>                         a href="+code=LongestChain" class="sref">LongestChain /a> =  a href="+code=chain" class="sref">chain /a>;n
448 /a>                }n
449 /a>        }n
450 /a>n
451 /a>        if (ChainLength /a> < 2) {n
452 /a>                 a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: no Virtual Unit Chains available " /spaion
453 /a>                         spai class="string">"for folding. Failing request\n" /spaio);n
454 /a>                return BLOCK_NIL /a>;n
455 /a>        }n
456 /a>n
457 /a>        return INFTL_foldchain /a>(inftl /a>,  a href="+code=LongestChain" class="sref">LongestChain /a>, pendingblock /a>);n
458 /a>}n
459 /a>n
460 /a>static int nrbits /a>(unsigned int val /a>, int bitcount /a>)n
461 /a>{n
462 /a>        int i /a>, total /a> = 0;n
463 /a>n
464 /a>        for (i /a> = 0; (i /a> < bitcount /a>); i /a>++)n
465 /a>                total /a> += (((0x1 << i /a>) & val /a>) ? 1 : 0);n
466 /a>        return total /a>;n
467 /a>}n
468 /a>n
469 /a> spai class="comment">/* /spaion
470 /a> spai class="comment"> * INFTL_findwriteunit: Return the unit number into which we cai write /spaion
471 /a> spai class="comment"> *                      for this block. Make it available if it isn't already. /spaion
472 /a> spai class="comment"> */ /spaion
473 /a>static  a href="+code=inline" class="sref">inline /a>  a href="+code=u16" class="sref">u16 /a>  a href="+code=INFTL_findwriteunit" class="sref">INFTL_findwriteunit /a>(struct INFTLrecord /a> *inftl /a>, unsigned block /a>)n
474 /a>{n
475 /a>        unsigned int thisVUC /a> =  a href="+code=block" class="sref">block /a> / (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> / SECTORSIZE /a>);n
476 /a>        unsigned int thisEUN /a>, writeEUN /a>, prev_block /a>, status /a>;n
477 /a>        unsigned long  a href="+code=blockofs" class="sref">blockofs /a> = (block /a> * SECTORSIZE /a>) & (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> -1);n
478 /a>        struct mtd_info /a> *mtd /a> = inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.mtd /a>;n
479 /a>        struct inftl_oob /a> oob /a>;n
480 /a>        struct inftl_bci /a> bci /a>;n
481 /a>        unsigned char  a href="+code=anac" class="sref">anac /a>, nacs /a>, parity /a>;n
482 /a>         a href="+code=size_t" class="sref">size_t /a> retlen /a>;n
483 /a>        int silly /a>, silly2 /a> = 3;n
484 /a>n
485 /a>        pr_debug /a>("INFTL: INFTL_findwriteunit(inftl=%p,block=%d)\n" /spaio,n
486 /a>                        inftl /a>,  a href="+code=block" class="sref">block /a>);n
487 /a>n
488 /a>        do {n
489 /a>                 spai class="comment">/* /spaion
490 /a> spai class="comment">                 * Scai the media to find a unit in the VUC which has /spaion
491 /a> spai class="comment">                 * a free space for the block in question. /spaion
492 /a> spai class="comment">                 */ /spaion
493 /a>                writeEUN /a> = BLOCK_NIL /a>;n
494 /a>                thisEUN /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>];n
495 /a>                silly /a> = MAX_LOOPS /a>;n
496 /a>n
497 /a>                while (thisEUN /a> <= inftl /a>-> a href="+code=lastEUN" class="sref">lastEUN /a>) {n
498 /a>                        inftl_read_oob /a>(mtd /a>, (thisEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>) +n
499 /a>                                       blockofs /a>, 8, & a href="+code=retlen" class="sref">retlen /a>, (char *)& a href="+code=bci" class="sref">bci /a>);n
500 /a>n
501 /a>                        status /a> =  a href="+code=bci" class="sref">bci /a>.Status /a> |  a href="+code=bci" class="sref">bci /a>.Status1 /a>;n
502 /a>                        pr_debug /a>("INFTL: status of block %d in EUN %d is %x\n" /spaio,n
503 /a>                                        block /a> , writeEUN /a>, status /a>);n
504 /a>n
505 /a>                        switch(status /a>) {n
506 /a>                        case SECTOR_FREE /a>:n
507 /a>                                writeEUN /a> = thisEUN /a>;n
508 /a>                                break;n
509 /a>                        case SECTOR_DELETED /a>:n
510 /a>                        case SECTOR_USED /a>:n
511 /a>                                 spai class="comment">/* Can't go any further */ /spaion
512 /a>                                goto hitused /a>;n
513 /a>                        case SECTOR_IGNORE /a>:n
514 /a>                                break;n
515 /a>                        default:n
516 /a>                                 spai class="comment">/* /spaion
517 /a> spai class="comment">                                 * Invalid block. Don't use it any more. /spaion
518 /a> spai class="comment">                                 * Must implement. /spaion
519 /a> spai class="comment">                                 */ /spaion
520 /a>                                break;n
521 /a>                        }n
522 /a>n
523 /a>                        if (!silly /a>--) {n
524 /a>                                printk /a>(KERN_WARNING /a> "INFTL: infinite loop in " /spaion
525 /a>                                         spai class="string">"Virtual Unit Chain 0x%x\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
526 /a>                                return BLOCK_NIL /a>;n
527 /a>                        }n
528 /a>n
529 /a>                         spai class="comment">/* Skip to next block in chain */ /spaion
530 /a>                         a href="+code=thisEUN" class="sref">thisEUN /a> = inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>];n
531 /a>                }n
532 /a>n
533 /a>hitused /a>:n
534 /a>                if (writeEUN /a> != BLOCK_NIL /a>)n
535 /a>                        return writeEUN /a>;n
536 /a>n
537 /a>n
538 /a>                 spai class="comment">/* /spaion
539 /a> spai class="comment">                 * OK. We didn't find one in the existing chain, or there /spaion
540 /a> spai class="comment">                 * is no existing chain. Allocate a new one. /spaion
541 /a> spai class="comment">                 */ /spaion
542 /a>                writeEUN /a> = INFTL_findfreeblock /a>(inftl /a>, 0);n
543 /a>n
544 /a>                if (writeEUN /a> == BLOCK_NIL /a>) {n
545 /a>                         spai class="comment">/* /spaion
546 /a> spai class="comment">                         * That didn't work - there were no free blocks just /spaion
547 /a> spai class="comment">                         * waiting to be picked up. We're going to have to fold /spaion
548 /a> spai class="comment">                         * a chain to make room. /spaion
549 /a> spai class="comment">                         */ /spaion
550 /a>                         a href="+code=thisEUN" class="sref">thisEUN /a> = INFTL_makefreeblock /a>(inftl /a>,  a href="+code=block" class="sref">block /a>);n
551 /a>n
552 /a>                         spai class="comment">/* /spaion
553 /a> spai class="comment">                         * Hopefully we free something, lets try again. /spaion
554 /a> spai class="comment">                         * This time we are desperate... /spaion
555 /a> spai class="comment">                         */ /spaion
556 /a>                        pr_debug /a>("INFTL: using desperate==1 to find free EUN " /spaion
557 /a>                                        "to accommodate write to VUC %d\n" /spaio,n
558 /a>                                        thisVUC /a>);n
559 /a>                         a href="+code=writeEUN" class="sref">writeEUN /a> = INFTL_findfreeblock /a>(inftl /a>, 1);n
560 /a>                        if (writeEUN /a> == BLOCK_NIL /a>) {n
561 /a>                                 spai class="comment">/* /spaion
562 /a> spai class="comment">                                 * Ouch. This should never happen - we should /spaion
563 /a> spai class="comment">                                 * always be able to make some room somehow. /spaion
564 /a> spai class="comment">                                 * If we get here, we've allocated more storage /spaion
565 /a> spai class="comment">                                 * space thai actual media, or our makefreeblock /spaion
566 /a> spai class="comment">                                 * routine is missing something. /spaion
567 /a> spai class="comment">                                 */ /spaion
568 /a>                                printk /a>(KERN_WARNING /a> "INFTL: cannot make free " /spaion
569 /a>                                        "space.\n" /spaio);n
570 /a>#ifdef DEBUG /a>n
571 /a>                                 a href="+code=INFTL_dumptables" class="sref">INFTL_dumptables /a>(inftl /a>);n
572 /a>                                 a href="+code=INFTL_dumpVUchains" class="sref">INFTL_dumpVUchains /a>(inftl /a>);n
573 /a>#endifn
574 /a>                                return BLOCK_NIL /a>;n
575 /a>                        }n
576 /a>                }n
577 /a>n
578 /a>                 spai class="comment">/* /spaion
579 /a> spai class="comment">                 * Insert new block into virtual chain. Firstly update the /spaion
580 /a> spai class="comment">                 * block headers in flash... /spaion
581 /a> spai class="comment">                 */ /spaion
582 /a>                anac /a> = 0;n
583 /a>                nacs /a> = 0;n
584 /a>                thisEUN /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>];n
585 /a>                if (thisEUN /a> != BLOCK_NIL /a>) {n
586 /a>                        inftl_read_oob /a>(mtd /a>, thisEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>n
587 /a>                                       + 8, 8, & a href="+code=retlen" class="sref">retlen /a>, (char *)& a href="+code=oob" class="sref">oob /a>.u /a>);n
588 /a>                        anac /a> =  a href="+code=oob" class="sref">oob /a>.u /a>.a /a>.ANAC /a> + 1;n
589 /a>                        nacs /a> =  a href="+code=oob" class="sref">oob /a>.u /a>.a /a>.NACs /a> + 1;n
590 /a>                }n
591 /a>n
592 /a>                 a href="+code=prev_block" class="sref">prev_block /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>];n
593 /a>                if (prev_block /a> < inftl /a>-> a href="+code=nb_blocks" class="sref">nb_blocks /a>)n
594 /a>                         a href="+code=prev_block" class="sref">prev_block /a> -= inftl /a>-> a href="+code=firstEUN" class="sref">firstEUN /a>;n
595 /a>n
596 /a>                 a href="+code=parity" class="sref">parity /a> = (nrbits /a>( a href="+code=thisVUC" class="sref">thisVUC /a>, 16) & 0x1) ? 0x1 : 0;n
597 /a>                 a href="+code=parity" class="sref">parity /a> |= (nrbits /a>( a href="+code=prev_block" class="sref">prev_block /a>, 16) & 0x1) ? 0x2 : 0;n
598 /a>                 a href="+code=parity" class="sref">parity /a> |= (nrbits /a>( a href="+code=anac" class="sref">anac /a>, 8) & 0x1) ? 0x4 : 0;n
599 /a>                 a href="+code=parity" class="sref">parity /a> |= (nrbits /a>( a href="+code=nacs" class="sref">nacs /a>, 8) & 0x1) ? 0x8 : 0;n
600 /a>n
601 /a>                 a href="+code=oob" class="sref">oob /a>.u /a>.a /a>.virtualUnitNo /a> = cpu_to_le16 /a>( a href="+code=thisVUC" class="sref">thisVUC /a>);n
602 /a>                 a href="+code=oob" class="sref">oob /a>.u /a>.a /a>.prevUnitNo /a> = cpu_to_le16 /a>( a href="+code=prev_block" class="sref">prev_block /a>);n
603 /a>                 a href="+code=oob" class="sref">oob /a>.u /a>.a /a>.ANAC /a> = anac /a>;n
604 /a>                oob /a>.u /a>.a /a>.NACs /a> = nacs /a>;n
605 /a>                oob /a>.u /a>.a /a>.parityPerField /a> = parity /a>;n
606 /a>                oob /a>.u /a>.a /a>.discarded /a> = 0xaa;n
607 /a>n
608 /a>                inftl_write_oob /a>(mtd /a>, writeEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> + 8, 8,n
609 /a>                                & a href="+code=retlen" class="sref">retlen /a>, (char *)& a href="+code=oob" class="sref">oob /a>.u /a>);n
610 /a>n
611 /a>                 spai class="comment">/* Also back up header... */ /spaion
612 /a>                oob /a>.u /a>.b /a>.virtualUnitNo /a> = cpu_to_le16 /a>( a href="+code=thisVUC" class="sref">thisVUC /a>);n
613 /a>                oob /a>.u /a>.b /a>.prevUnitNo /a> = cpu_to_le16 /a>( a href="+code=prev_block" class="sref">prev_block /a>);n
614 /a>                oob /a>.u /a>.b /a>.ANAC /a> = anac /a>;n
615 /a>                oob /a>.u /a>.b /a>.NACs /a> = nacs /a>;n
616 /a>                oob /a>.u /a>.b /a>.parityPerField /a> = parity /a>;n
617 /a>                 a href="+code=oob" class="sref">oob /a>.u /a>.b /a>.discarded /a> = 0xaa;n
618 /a>n
619 /a>                 a href="+code=inftl_write_oob" class="sref">inftl_write_oob /a>(mtd /a>, writeEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> +n
620 /a>                                 a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a> * 4 + 8, 8, & a href="+code=retlen" class="sref">retlen /a>, (char *)& a href="+code=oob" class="sref">oob /a>.u /a>);n
621 /a>n
622 /a>                inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=writeEUN" class="sref">writeEUN /a>] = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>];n
623 /a>                inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>] = writeEUN /a>;n
624 /a>n
625 /a>                inftl /a>-> a href="+code=numfreeEUNs" class="sref">numfreeEUNs /a>--;n
626 /a>                return writeEUN /a>;n
627 /a>n
628 /a>        } while (silly2 /a>--);n
629 /a>n
630 /a>         a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: error folding to make room for Virtual " /spaion
631 /a>                "Unit Chain 0x%x\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
632 /a>        return BLOCK_NIL /a>;n
633 /a>}n
634 /a>n
635 /a> spai class="comment">/* /spaion
636 /a> spai class="comment"> * Given a Virtual Unit Chain, see if it cai be deleted, and if so do it. /spaion
637 /a> spai class="comment"> */ /spaion
638 /a>static void INFTL_trydeletechain /a>(struct INFTLrecord /a> *inftl /a>, unsigned thisVUC /a>)n
639 /a>{n
640 /a>        struct mtd_info /a> *mtd /a> = inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.mtd /a>;n
641 /a>        unsigned char  a href="+code=BlockUsed" class="sref">BlockUsed /a>[ a href="+code=MAX_SECTORS_PER_UNIT" class="sref">MAX_SECTORS_PER_UNIT /a>];n
642 /a>        unsigned char  a href="+code=BlockDeleted" class="sref">BlockDeleted /a>[ a href="+code=MAX_SECTORS_PER_UNIT" class="sref">MAX_SECTORS_PER_UNIT /a>];n
643 /a>        unsigned int thisEUN /a>, status /a>;n
644 /a>        int block /a>, silly /a>;n
645 /a>        struct inftl_bci /a> bci /a>;n
646 /a>        size_t /a> retlen /a>;n
647 /a>n
648 /a>        pr_debug /a>("INFTL: INFTL_trydeletechain(inftl=%p," /spaion
649 /a>                 spai class="string">"thisVUC=%d)\n" /spaio, inftl /a>,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
650 /a>n
651 /a>        memset /a>(BlockUsed /a>, 0, sizeof(BlockUsed /a>));n
652 /a>        memset /a>(BlockDeleted /a>, 0, sizeof(BlockDeleted /a>));n
653 /a>n
654 /a>        thisEUN /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>];n
655 /a>        if (thisEUN /a> == BLOCK_NIL /a>) {n
656 /a>                 a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: trying to delete non-existent " /spaion
657 /a>                        spai class="string">"Virtual Unit Chain %d!\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
658 /a>                return;n
659 /a>        }n
660 /a>n
661 /a>         spai class="comment">/* /spaion
662 /a> spai class="comment">         * Scai through the Erase Units to determine whether any data is in /spaion
663 /a> spai class="comment">         * each of the 512-byte blocks within the Chain. /spaion
664 /a> spai class="comment">         */ /spaion
665 /a>        silly /a> = MAX_LOOPS /a>;n
666 /a>        while (thisEUN /a> < inftl /a>-> a href="+code=nb_blocks" class="sref">nb_blocks /a>) {n
667 /a>                for (block /a> = 0; block /a> < inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>/ a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a>; block /a>++) {n
668 /a>                        if (BlockUsed /a>[ a href="+code=block" class="sref">block /a>] ||  a href="+code=BlockDeleted" class="sref">BlockDeleted /a>[ a href="+code=block" class="sref">block /a>])n
669 /a>                                continue;n
670 /a>n
671 /a>                        if (inftl_read_oob /a>(mtd /a>, (thisEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>)n
672 /a>                                           + (block /a> * SECTORSIZE /a>), 8 , & a href="+code=retlen" class="sref">retlen /a>,n
673 /a>                                          (char *)& a href="+code=bci" class="sref">bci /a>) < 0)n
674 /a>                                status /a> = SECTOR_IGNORE /a>;n
675 /a>                        elsen
676 /a>                                status /a> = bci /a>.Status /a> |  a href="+code=bci" class="sref">bci /a>.Status1 /a>;n
677 /a>n
678 /a>                        switch(status /a>) {n
679 /a>                        case SECTOR_FREE /a>:n
680 /a>                        case SECTOR_IGNORE /a>:n
681 /a>                                break;n
682 /a>                        case SECTOR_USED /a>:n
683 /a>                                BlockUsed /a>[ a href="+code=block" class="sref">block /a>] = 1;n
684 /a>                                continue;n
685 /a>                        case SECTOR_DELETED /a>:n
686 /a>                                BlockDeleted /a>[ a href="+code=block" class="sref">block /a>] = 1;n
687 /a>                                continue;n
688 /a>                        default:n
689 /a>                                printk /a>(KERN_WARNING /a> "INFTL: unknown status " /spaion
690 /a>                                        "for block %d in EUN %d: 0x%x\n" /spaio,n
691 /a>                                        block /a>, thisEUN /a>, status /a>);n
692 /a>                        }n
693 /a>                }n
694 /a>n
695 /a>                if (!silly /a>--) {n
696 /a>                        printk /a>(KERN_WARNING /a> "INFTL: infinite loop in Virtual " /spaion
697 /a>                                "Unit Chain 0x%x\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
698 /a>                        return;n
699 /a>                }n
700 /a>n
701 /a>                 a href="+code=thisEUN" class="sref">thisEUN /a> = inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>];n
702 /a>        }n
703 /a>n
704 /a>        for (block /a> = 0; block /a> < inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>/ a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a>; block /a>++)n
705 /a>                if (BlockUsed /a>[ a href="+code=block" class="sref">block /a>])n
706 /a>                        return;n
707 /a>n
708 /a>         spai class="comment">/* /spaion
709 /a> spai class="comment">         * For each block in the chain free it and make it available /spaion
710 /a> spai class="comment">         * for future use. Erase from the oldest unit first. /spaion
711 /a> spai class="comment">         */ /spaion
712 /a>        pr_debug /a>("INFTL: deleting empty VUC %d\n" /spaio,  a href="+code=thisVUC" class="sref">thisVUC /a>);n
713 /a>n
714 /a>        for (;;) {n
715 /a>                u16 /a> *prevEUN /a> = & a href="+code=inftl" class="sref">inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>];n
716 /a>                thisEUN /a> = *prevEUN /a>;n
717 /a>n
718 /a>                 spai class="comment">/* If the chain is all gone already, we're done */ /spaion
719 /a>                if (thisEUN /a> == BLOCK_NIL /a>) {n
720 /a>                        pr_debug /a>("INFTL: Empty VUC %d for deletion was already absent\n" /spaio,  a href="+code=thisEUN" class="sref">thisEUN /a>);n
721 /a>                        return;n
722 /a>                }n
723 /a>n
724 /a>                /* Find oldest unit in chain. */ /spaion
725 /a>                while (inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>] != BLOCK_NIL /a>) {n
726 /a>                        BUG_ON /a>(thisEUN /a> >= inftl /a>-> a href="+code=nb_blocks" class="sref">nb_blocks /a>);n
727 /a>n
728 /a>                        prevEUN /a> = & a href="+code=inftl" class="sref">inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>];n
729 /a>                        thisEUN /a> = *prevEUN /a>;n
730 /a>                }n
731 /a>n
732 /a>                pr_debug /a>("Deleting EUN %d from VUC %d\n" /spaio,n
733 /a>                      thisEUN /a>, thisVUC /a>);n
734 /a>n
735 /a>                if (INFTL_formatblock /a>(inftl /a>,  a href="+code=thisEUN" class="sref">thisEUN /a>) < 0) {n
736 /a>                        /* /spaion
737 /a> spai class="comment">                         * Could not erase : mark block as reserved. /spaion
738 /a> spai class="comment">                         */ /spaion
739 /a>                        inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>] = BLOCK_RESERVED /a>;n
740 /a>                } else {n
741 /a>                        /* Correctly erased : mark it as free */ /spaion
742 /a>                        inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>] = BLOCK_FREE /a>;n
743 /a>                        inftl /a>-> a href="+code=numfreeEUNs" class="sref">numfreeEUNs /a>++;n
744 /a>                }n
745 /a>n
746 /a>                /* Now sort out whatever was pointing to it... */ /spaion
747 /a>                *prevEUN /a> = BLOCK_NIL /a>;n
748 /a>n
749 /a>                 spai class="comment">/* Ideally we'd actually be responsive to new /spaion
750 /a> spai class="comment">                   requests while we're doing this -- if there's /spaion
751 /a> spai class="comment">                   free space why should others be made to wait? */ /spaion
752 /a>                cond_resched /a>();n
753 /a>        }n
754 /a>n
755 /a>        inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=thisVUC" class="sref">thisVUC /a>] = BLOCK_NIL /a>;n
756 /a>}n
757 /a>n
758 /a>static int INFTL_deleteblock /a>(struct INFTLrecord /a> *inftl /a>, unsigned block /a>)n
759 /a>{n
760 /a>        unsigned int thisEUN /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=block" class="sref">block /a> / (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> / SECTORSIZE /a>)];n
761 /a>        unsigned long  a href="+code=blockofs" class="sref">blockofs /a> = (block /a> * SECTORSIZE /a>) & (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> - 1);n
762 /a>        struct mtd_info /a> *mtd /a> = inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.mtd /a>;n
763 /a>        unsigned int status /a>;n
764 /a>        int silly /a> = MAX_LOOPS /a>;n
765 /a>        size_t /a> retlen /a>;n
766 /a>        struct inftl_bci /a> bci /a>;n
767 /a>n
768 /a>        pr_debug /a>("INFTL: INFTL_deleteblock(inftl=%p," /spaion
769 /a>                "block=%d)\n" /spaio, inftl /a>,  a href="+code=block" class="sref">block /a>);n
770 /a>n
771 /a>        while (thisEUN /a> < inftl /a>-> a href="+code=nb_blocks" class="sref">nb_blocks /a>) {n
772 /a>                if (inftl_read_oob /a>(mtd /a>, (thisEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>) +n
773 /a>                                    a href="+code=blockofs" class="sref">blockofs /a>, 8, & a href="+code=retlen" class="sref">retlen /a>, (char *)& a href="+code=bci" class="sref">bci /a>) < 0)n
774 /a>                        status /a> = SECTOR_IGNORE /a>;n
775 /a>                elsen
776 /a>                        status /a> = bci /a>.Status /a> |  a href="+code=bci" class="sref">bci /a>.Status1 /a>;n
777 /a>n
778 /a>                switch (status /a>) {n
779 /a>                case SECTOR_FREE /a>:n
780 /a>                case SECTOR_IGNORE /a>:n
781 /a>                        break;n
782 /a>                case SECTOR_DELETED /a>:n
783 /a>                        thisEUN /a> = BLOCK_NIL /a>;n
784 /a>                        goto foundit /a>;n
785 /a>                case SECTOR_USED /a>:n
786 /a>                        goto foundit /a>;n
787 /a>                default:n
788 /a>                        printk /a>(KERN_WARNING /a> "INFTL: unknown status for " /spaion
789 /a>                                "block %d in EUN %d: 0x%x\n" /spaio,n
790 /a>                                 a href="+code=block" class="sref">block /a>, thisEUN /a>, status /a>);n
791 /a>                        break;n
792 /a>                }n
793 /a>n
794 /a>                if (!silly /a>--) {n
795 /a>                         a href="+code=printk" class="sref">printk /a>(KERN_WARNING /a> "INFTL: infinite loop in Virtual " /spaion
796 /a>                                 spai class="string">"Unit Chain 0x%x\n" /spaio,n
797 /a>                                block /a> / (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> / SECTORSIZE /a>));n
798 /a>                        return 1;n
799 /a>                }n
800 /a>                thisEUN /a> = inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>];n
801 /a>        }n
802 /a>n
803 /a>foundit /a>:n
804 /a>        if (thisEUN /a> != BLOCK_NIL /a>) {n
805 /a>                loff_t /a> ptr /a> = (thisEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>) +  a href="+code=blockofs" class="sref">blockofs /a>;n
806 /a>n
807 /a>                if (inftl_read_oob /a>(mtd /a>, ptr /a>, 8, & a href="+code=retlen" class="sref">retlen /a>, (char *)& a href="+code=bci" class="sref">bci /a>) < 0)n
808 /a>                        return - a href="+code=EIO" class="sref">EIO /a>;n
809 /a>                bci /a>.Status /a> = bci /a>.Status1 /a> = SECTOR_DELETED /a>;n
810 /a>                if (inftl_write_oob /a>(mtd /a>, ptr /a>, 8, & a href="+code=retlen" class="sref">retlen /a>, (char *)& a href="+code=bci" class="sref">bci /a>) < 0)n
811 /a>                        return - a href="+code=EIO" class="sref">EIO /a>;n
812 /a>                INFTL_trydeletechain /a>(inftl /a>,  a href="+code=block" class="sref">block /a> / (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> / SECTORSIZE /a>));n
813 /a>        }n
814 /a>        return 0;n
815 /a>}n
816 /a>n
817 /a>static int inftl_writeblock /a>(struct mtd_blktrans_dev /a> *mbd /a>, unsigned long  a href="+code=block" class="sref">block /a>,n
818 /a>                            char * a href="+code=buffer" class="sref">buffer /a>)n
819 /a>{n
820 /a>        struct INFTLrecord /a> *inftl /a> = (void *)mbd /a>;n
821 /a>        unsigned int writeEUN /a>;n
822 /a>        unsigned long  a href="+code=blockofs" class="sref">blockofs /a> = (block /a> * SECTORSIZE /a>) & (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> - 1);n
823 /a>        size_t /a> retlen /a>;n
824 /a>        struct inftl_oob /a> oob /a>;n
825 /a>        char * a href="+code=p" class="sref">p /a>, * a href="+code=pend" class="sref">pend /a>;n
826 /a>n
827 /a>        pr_debug /a>("INFTL: inftl_writeblock(inftl=%p,block=%ld," /spaion
828 /a>                "buffer=%p)\n" /spaio, inftl /a>,  a href="+code=block" class="sref">block /a>,  a href="+code=buffer" class="sref">buffer /a>);n
829 /a>n
830 /a>         spai class="comment">/* Is block all zero? */ /spaion
831 /a>        pend /a> = buffer /a> +  a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a>;n
832 /a>        for (p /a> = buffer /a>; p /a> < pend /a> && !* a href="+code=p" class="sref">p /a>; p /a>++)n
833 /a>                ;n
834 /a>n
835 /a>        if (p /a> < pend /a>) {n
836 /a>                writeEUN /a> = INFTL_findwriteunit /a>(inftl /a>,  a href="+code=block" class="sref">block /a>);n
837 /a>n
838 /a>                if (writeEUN /a> == BLOCK_NIL /a>) {n
839 /a>                        printk /a>(KERN_WARNING /a> "inftl_writeblock(): cannot find " /spaion
840 /a>                                "block to write to\n" /spaio);n
841 /a>                        /* /spaion
842 /a> spai class="comment">                         * If we _still_ haven't got a block to use, /spaion
843 /a> spai class="comment">                         * we're screwed. /spaion
844 /a> spai class="comment">                         */ /spaion
845 /a>                        return 1;n
846 /a>                }n
847 /a>n
848 /a>                memset /a>(& a href="+code=oob" class="sref">oob /a>, 0xff, sizeof(struct inftl_oob /a>));n
849 /a>                 a href="+code=oob" class="sref">oob /a>.b /a>.Status /a> = oob /a>.b /a>.Status1 /a> = SECTOR_USED /a>;n
850 /a>n
851 /a>                 a href="+code=inftl_write" class="sref">inftl_write /a>(inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.mtd /a>, (writeEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>) +n
852 /a>                             a href="+code=blockofs" class="sref">blockofs /a>,  a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a>, & a href="+code=retlen" class="sref">retlen /a>, (char *)buffer /a>,n
853 /a>                            (char *)& a href="+code=oob" class="sref">oob /a>);n
854 /a>                /* /spaion
855 /a> spai class="comment">                 * need to write SECTOR_USED flags since they are not written /spaion
856 /a> spai class="comment">                 * in mtd_writeecc /spaion
857 /a> spai class="comment">                 */ /spaion
858 /a>        } else {n
859 /a>                 a href="+code=INFTL_deleteblock" class="sref">INFTL_deleteblock /a>(inftl /a>,  a href="+code=block" class="sref">block /a>);n
860 /a>        }n
861 /a>n
862 /a>        return 0;n
863 /a>}n
864 /a>n
865 /a>static int inftl_readblock /a>(struct mtd_blktrans_dev /a> *mbd /a>, unsigned long  a href="+code=block" class="sref">block /a>,n
866 /a>                           char * a href="+code=buffer" class="sref">buffer /a>)n
867 /a>{n
868 /a>        struct INFTLrecord /a> *inftl /a> = (void *)mbd /a>;n
869 /a>        unsigned int thisEUN /a> = inftl /a>-> a href="+code=VUtable" class="sref">VUtable /a>[ a href="+code=block" class="sref">block /a> / (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> / SECTORSIZE /a>)];n
870 /a>        unsigned long  a href="+code=blockofs" class="sref">blockofs /a> = (block /a> * SECTORSIZE /a>) & (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> - 1);n
871 /a>        struct mtd_info /a> *mtd /a> = inftl /a>-> a href="+code=mbd" class="sref">mbd /a>.mtd /a>;n
872 /a>        unsigned int status /a>;n
873 /a>        int silly /a> = MAX_LOOPS /a>;n
874 /a>        struct inftl_bci /a> bci /a>;n
875 /a>        size_t /a> retlen /a>;n
876 /a>n
877 /a>        pr_debug /a>("INFTL: inftl_readblock(inftl=%p,block=%ld," /spaion
878 /a>                "buffer=%p)\n" /spaio, inftl /a>,  a href="+code=block" class="sref">block /a>,  a href="+code=buffer" class="sref">buffer /a>);n
879 /a>n
880 /a>        while (thisEUN /a> < inftl /a>-> a href="+code=nb_blocks" class="sref">nb_blocks /a>) {n
881 /a>                if (inftl_read_oob /a>(mtd /a>, (thisEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>) +n
882 /a>                                   a href="+code=blockofs" class="sref">blockofs /a>, 8, & a href="+code=retlen" class="sref">retlen /a>, (char *)& a href="+code=bci" class="sref">bci /a>) < 0)n
883 /a>                        status /a> = SECTOR_IGNORE /a>;n
884 /a>                elsen
885 /a>                        status /a> = bci /a>.Status /a> |  a href="+code=bci" class="sref">bci /a>.Status1 /a>;n
886 /a>n
887 /a>                switch (status /a>) {n
888 /a>                case SECTOR_DELETED /a>:n
889 /a>                        thisEUN /a> = BLOCK_NIL /a>;n
890 /a>                        goto foundit /a>;n
891 /a>                case SECTOR_USED /a>:n
892 /a>                        goto foundit /a>;n
893 /a>                case SECTOR_FREE /a>:n
894 /a>                case SECTOR_IGNORE /a>:n
895 /a>                        break;n
896 /a>                default:n
897 /a>                        printk /a>(KERN_WARNING /a> "INFTL: unknown status for " /spaion
898 /a>                                "block %ld in EUN %d: 0x%04x\n" /spaio,n
899 /a>                                block /a>, thisEUN /a>, status /a>);n
900 /a>                        break;n
901 /a>                }n
902 /a>n
903 /a>                if (!silly /a>--) {n
904 /a>                        printk /a>(KERN_WARNING /a> "INFTL: infinite loop in " /spaion
905 /a>                                "Virtual Unit Chain 0x%lx\n" /spaio,n
906 /a>                                 a href="+code=block" class="sref">block /a> / (inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a> / SECTORSIZE /a>));n
907 /a>                        return 1;n
908 /a>                }n
909 /a>n
910 /a>                thisEUN /a> = inftl /a>-> a href="+code=PUtable" class="sref">PUtable /a>[ a href="+code=thisEUN" class="sref">thisEUN /a>];n
911 /a>        }n
912 /a>n
913 /a>foundit /a>:n
914 /a>        if (thisEUN /a> == BLOCK_NIL /a>) {n
915 /a>                /* The requested block is not on the media, return all 0x00 */ /spaion
916 /a>                memset /a>( a href="+code=buffer" class="sref">buffer /a>, 0,  a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a>);n
917 /a>        } else {n
918 /a>                size_t /a> retlen /a>;n
919 /a>                 a href="+code=loff_t" class="sref">loff_t /a> ptr /a> = (thisEUN /a> * inftl /a>-> a href="+code=EraseSize" class="sref">EraseSize /a>) +  a href="+code=blockofs" class="sref">blockofs /a>;n
920 /a>                int ret /a> = mtd_read /a>(mtd /a>, ptr /a>,  a href="+code=SECTORSIZE" class="sref">SECTORSIZE /a>, & a href="+code=retlen" class="sref">retlen /a>,  a href="+code=buffer" class="sref">buffer /a>);n
921 /a>n
922 /a>                /* Handle corrected bit flips gracefully */ /spaion
923 /a>                if (ret /a> < 0 && !mtd_is_bitflip /a>(ret /a>))n
924 /a>                        return - a href="+code=EIO" class="sref">EIO /a>;n
925 /a>        }n
926 /a>        return 0;n
927 /a>}n
928 /a>n
929 /a>static int inftl_getgeo /a>(struct mtd_blktrans_dev /a> *dev /a>, struct hd_geometry /a> *geo /a>)n
930 /a>{n
931 /a>        struct INFTLrecord /a> *inftl /a> = (void *)dev /a>;n
932 /a>n
933 /a>        geo /a>-> a href="+code=heads" class="sref">heads /a> = inftl /a>-> a href="+code=heads" class="sref">heads /a>;n
934 /a>        geo /a>-> a href="+code=sectors" class="sref">sectors /a> = inftl /a>-> a href="+code=sectors" class="sref">sectors /a>;n
935 /a>        geo /a>-> a href="+code=cylinders" class="sref">cylinders /a> = inftl /a>-> a href="+code=cylinders" class="sref">cylinders /a>;n
936 /a>n
937 /a>        return 0;n
938 /a>}n
939 /a>n
940 /a>static struct mtd_blktrans_ops /a> inftl_tr /a> = {n
941 /a>        .naml /a>           = "inftl" /spaio,n
942 /a>        .major /a>          = INFTL_MAJOR /a>,n
943 /a>        .part_bits /a>      = INFTL_PARTN_BITS /a>,n
944 /a>        .blksize /a>        = 512,n
945 /a>        .getgeo /a>         = inftl_getgeo /a>,n
946 /a>        .readsect /a>       = inftl_readblock /a>,n
947 /a>        .writesect /a>      = inftl_writeblock /a>,n
948 /a>        .add_mtd /a>        = inftl_add_mtd /a>,n
949 /a>        .remove_dev /a>     = inftl_remove_dev /a>,n
950 /a>        .owner /a>          = THIS_MODULE /a>,n
951 /a>};n
952 /a>n
953 /a>static int __init /a> init_inftl /a>(void)n
954 /a>{n
955 /a>        return register_mtd_blktrans /a>(& a href="+code=inftl_tr" class="sref">inftl_tr /a>);n
956 /a>}n
957 /a>n
958 /a>static void __exit /a> cleanup_inftl /a>(void)n
959 /a>{n
960 /a>        deregister_mtd_blktrans /a>(& a href="+code=inftl_tr" class="sref">inftl_tr /a>);n
961 /a>}n
962 /a>n
963 /a>module_init /a>(init_inftl /a>);n
964 /a>module_exit /a>(cleanup_inftl /a>);n
965 /a>n
966 /a>MODULE_LICENSE /a>("GPL" /spaio);n
967 /a>MODULE_AUTHOR /a>("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al." /spaio);n
968 /a>MODULE_DESCRIPTION /a>("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus" /spaio);n
969 /a>
lxr.linux.no kindly hosted by Redpill Linpro AS /a>, provider of Linux consulting and operations services since 1995.