blob: b09118ca002644a5f807e208185e696aeb391a03 [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/*
2 * Linux driver for NAND NV Flash Translation Layer
3 * Copyright (C) 2013, ZTE Corporation.
4 */
5
6
7#include <linux/mtd/mtd.h>
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <asm/errno.h>
11#include <asm/io.h>
12#include <asm/uaccess.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/init.h>
16#include <linux/hdreg.h>
17#include <linux/blkdev.h>
18
19#include <linux/kmod.h>
20#include <linux/mtd/mtd.h>
21#include <linux/mtd/nand.h>
22
23#include <linux/mtd/blktrans.h>
24#include <linux/mtd/zftl.h>
25#include <linux/mtd/zftl_ecc.h>
26
27
28
29#include <linux/types.h>
30#include <linux/mtd/map.h>
31#include <linux/mtd/partitions.h>
32#include <asm/io.h>
33
34#ifdef CONFIG_MTD_NVRESUME
35#include <linux/mfd/zx234290.h>
36#endif
37
38#include <linux/mtd/partition_guard.h>
39
40#define ZFTL_DEBUG 0
41
42
43/* DEBUG */
44#if ZFTL_DEBUG
45#define zftl_debug(fmt,args...) printk (fmt ,##args)
46#define zftl_debugX(level,fmt,args...) if (DEBUG>=level) printk(fmt,##args);
47#else
48#define zftl_debug(fmt,args...)
49#define zftl_debugX(level,fmt,args...)
50#endif /* DEBUG */
51
52/* defined in cmd_nand.c */
53int arg_off_size(int argc, char *const argv[], int *idx,
54 loff_t *off, loff_t *size);
55extern int nand_block_isbad(struct mtd_info *mtd, loff_t offs);
56int zftl_unpack_tags(struct zftl_packed_tags *pt);
57
58
59#ifdef CONFIG_MTD_NVRESUME
60int zftl_res = 0;
61extern int hal_Comm_Soft_Reset(T_ZDrvSys_RESET_TYPE reset_type);
62extern int zOss_NvInResume(void);
63extern void zOss_NvSetErrorAddr(int dwAddr);
64#endif
65
66struct ZFTLrecord *zftl_info[CONFIG_ZFTL_MAX_PARTITIONS] = {NULL};
67extern struct mtd_info *mtd_fota;
68extern struct cmdline_mtd_partition *partitions;
69
70struct cmdline_mtd_partition {
71 struct cmdline_mtd_partition *next;
72 char *mtd_id;
73 int num_parts;
74 struct mtd_partition *parts;
75};
76
77int partnum = 0;
78static struct mutex zftl_mutex;
79static int mutex_inited = 0;
80int cdrom_partsize = 0;
81
82/* nvro partition size */
83int nvro_partsize = 0;
84int nvrwo_partsize = 0;
85
86
87int nand_NvProgram(int dwStart, int dwLen, char* from);
88int nand_NvRead(int dwStart, int dwLen, char* to);
89
90
91static int memcmpb(void *a, int c, int n)
92{
93 int i;
94 for (i = 0; i < n; i++) {
95 if (c != ((unsigned char *)a)[i])
96 return 1;
97 }
98 return 0;
99}
100
101/* Read oob data from flash */
102static int zftl_read_oob(struct ZFTLrecord *zftl, uint32_t offs, uint8_t *buf)
103{
104 nand_info_t *nand = zftl->nand;
105 uint32_t mask = zftl->writesize - 1;
106 struct mtd_oob_ops ops;
107 int32_t res;
108 struct zftl_packed_tags pt;
109
110 ops.mode = MTD_OPS_AUTO_OOB;
111 ops.ooboffs = offs & mask;
112
113 #ifdef CONFIG_ZFTL_ENABLE_OOB_ECC
114 ops.ooblen = sizeof(struct zftl_packed_tags);
115 ops.oobbuf = (uint8_t*)&pt;
116 #else
117 ops.ooblen = sizeof(struct zftl_oob);
118 ops.oobbuf = buf;
119 #endif
120 ops.datbuf = NULL;
121
122 res = nand->_read_oob(nand, (offs & ~mask), &ops);
123
124 #ifdef CONFIG_ZFTL_ENABLE_OOB_ECC
125 zftl_unpack_tags(&pt);
126 memcpy(buf,(uint8_t *)&(pt.t),sizeof(struct zftl_oob ));
127 #endif
128
129 return res;
130}
131
132
133static int zftl_setup_table(struct ZFTLrecord *zftl, uint32_t *is_writed)
134{
135 nand_info_t *nand = zftl->nand;
136 uint32_t block_num = zftl->numBlocks;
137 uint32_t first_block = zftl->firstBlock;
138 uint32_t erasesize = zftl->erasesize;
139 uint32_t oobsize = zftl->oobsize;
140 struct zftl_oob *oob = (struct zftl_oob *)zftl->oobbuf;
141 uint32_t index = 0;
142 uint32_t addr = 0;
143
144 memset(oob, 0x0, oobsize);
145
146 for( index = 0; index < block_num; index++ )
147 {
148 addr = (first_block + index) * erasesize;
149 if(nand->_block_isbad(nand, (loff_t)addr))
150 {
151 zftl->blockTable[index] = BLOCK_BAD;
152 continue;
153 }
154
155 /* д¿éµÄ˳ÐòΪ ÏÈдµÚ¶þÒ³¿ªÊ¼µ½×îºóÒ»Ò³£¬ÔÙдµÚÒ»Ò³ */
156 /* µÚÒ»Ò³oob µÚ¶þÒ³oob ¿é״̬ ˵Ã÷ */
157 /* 0xff 0xff BLOCK_FREE ¶¼Ã»ÓпªÊ¼Ð´ */
158 /* 0xff ---- BLOCK_DIRTY ¿ªÊ¼Ð´£¬µ«Ã»ÓÐдÍêµÚÒ»Ò³£¬Öм䱻ÖÐ¶Ï */
159 /* ---- 0xff BLOCK_USED/DIRTY дÍêµÚÒ»Ò³£¬Íê³É¿éдÈë */
160 /* ---- ---- BLOCK_USED/DIRTY дÍêµÚÒ»Ò³£¬Íê³É¿éдÈë */
161
162 if(zftl_read_oob(zftl, addr, (uint8_t *)oob ))/* ¶ÁÈ¡µÚÒ»Ò³ */
163 {
164 printk("[zftl_setup_table] read oob error at = 0x%08x\n", addr);
165 return NAND_READ_WRITE_ERROR;
166 }
167
168 if(memcmpb(oob, 0xff, oobsize)) /* µÚÒ»Ò³oob != 0xff */
169 {
170 //if( oob.used == 1 ) /* block is used */
171 if( !memcmp(oob->head, CONFIG_ZFLT_HEAD, CONFIG_ZFLT_HEAD_BYTE) ) /* °üº¬ÓзÖÇøÍ· */
172 {
173 *is_writed += 1;
174 if( oob->version > zftl->versionTable[oob->logicBlockID])
175 {
176 /* version is newer */
177 if(zftl->versionTable[oob->logicBlockID] != 0) /* ÒѾ­ÓжÔÓ¦µÄused¿éÁË */
178 zftl->blockTable[zftl->blockRepTable[oob->logicBlockID]] = BLOCK_DIRTY;
179
180 zftl->blockRepTable[oob->logicBlockID] = index;
181 zftl->versionTable[oob->logicBlockID] = oob->version;
182 zftl->blockTable[index] = BLOCK_USED;
183 /* Added by zhouqi for xxx, 2014/04/23 */
184 zftl->lastFreeBlock = index + 1;
185 }
186 else
187 zftl->blockTable[index] = BLOCK_DIRTY;
188 }
189 else
190 zftl->blockTable[index] = BLOCK_DIRTY;
191 }
192 else /* 0xff£¬block is free */
193 {
194 if(zftl_read_oob(zftl, addr + zftl->writesize, (uint8_t *)oob ))/* ¶ÁÈ¡µÚ¶þÒ³ */
195 {
196 printk("[zftl_setup_table] read oob error at = 0x%08x\n", addr);
197 return NAND_READ_WRITE_ERROR;
198 }
199
200 if(memcmpb(oob, 0xff, oobsize)) /* µÚ¶þÒ³oob != 0xff */
201 {
202 zftl->blockTable[index] = BLOCK_DIRTY;
203 }
204 else /* µÚ¶þÒ³oob = 0xff */
205 zftl->blockTable[index] = BLOCK_FREE;
206 }
207 }
208
209 return 0;
210}
211
212
213/* ²Á³ýÒ»¿é£¬ebnumΪ¿éºÅ */
214static int zftl_erase_block(nand_info_t *nand, uint32_t ebnum)
215{
216 int err = -1;
217 struct erase_info ei;
218 uint32_t addr = ebnum * nand->erasesize;
219
220 memset(&ei, 0, sizeof(struct erase_info));
221 ei.mtd = nand;
222 ei.addr = (uint64_t)addr;
223 ei.len = (uint64_t)nand->erasesize;
224
225 err = nand->_erase(nand, &ei);
226 if (err)
227 {
228 printk("[zftl_erase_block]: erasing %d error %d\n", ebnum, err);
229 return err;
230 }
231
232 if (ei.state == MTD_ERASE_FAILED)
233 {
234 printk("[zftl_erase_block]: erasing %d\n",ebnum);
235 return -1;
236 }
237 return 0;
238}
239
240
241void zftl_garbage_collect(struct ZFTLrecord *zftl)
242{
243 uint32_t block_num = zftl->numBlocks;
244 uint32_t firstBlock = zftl->firstBlock;
245 uint32_t index = 0;
246 nand_info_t *nand = zftl->nand;
247
248 zftl_debug("\n");
249
250 for( index = 0; index < block_num; index++ )
251 {
252 if( zftl->blockTable[index] == BLOCK_DIRTY )
253 {
254 zftl_debug(" [zftl_garbage_collect] eraseblock zftl->blockTable[-%d-]\n", index);
255 if( zftl_erase_block(nand, firstBlock + index) )
256 {
257 /* ²Á³ýʧ°Ü£¬±ê¼ÇΪ»µ¿ì */
258 zftl_debug(" [zftl_garbage_collect] eraseblock zftl->blockTable[-%d-] ERROR\n", index);
259 zftl->blockTable[index] = BLOCK_BAD;
260 /* ±ê¼Ç»µ¿é£¬¸üлµ¿é±í mtd->erase ÖУ¬ÒÔ°üº¬²Á³ýʧ°Ü¸üÐÂBBT*/
261 nand->_block_markbad(nand, (loff_t)((firstBlock + index) << zftl->erasesize_shift));
262 }
263 else
264 {
265 /* ²Á³ý³É¹¦ */
266 zftl->blockTable[index] = BLOCK_FREE;;
267 }
268 }
269 }
270 zftl_debug("\n");
271}
272
273
274/* Added by zhouqi for xxx, 2014/04/23 */
275
276static int zftl_find_free_block(struct ZFTLrecord *zftl, uint32_t *freeBlock)
277 {
278 uint32_t i = 2;
279 uint32_t index = 0;
280 uint32_t max = 0;
281
282 do
283 {
284 index = zftl->lastFreeBlock;
285 max = zftl->numBlocks;
286 for( ; index < max; index++ )
287 {
288 if( zftl->blockTable[index] == BLOCK_FREE )
289 {
290 *freeBlock = index ;
291 zftl->lastFreeBlock = index + 1;
292 zftl_debug(" [zftl_find_free_block++] zftl->blockTable[ -%d- ] -BLOCK_FREE-\n", index - 1);
293 return 0;
294 }
295 }
296
297 max = zftl->lastFreeBlock;
298 index = 1;
299 for( ; index < max; index++ )
300 {
301 if( zftl->blockTable[index - 1] == BLOCK_FREE )
302 {
303 *freeBlock = index - 1;
304 zftl->lastFreeBlock = index;
305 zftl_debug(" [zftl_find_free_block--] zftl->blockTable[ -%d- ] -BLOCK_FREE-\n", index - 1);
306 return 0;
307 }
308 }
309
310 /* ûÓÐÕÒµ½¿ÕÏеĿ飬Ôò½øÐÐÀ¬»ø»ØÊÕ */
311 zftl_debug(" [zftl_find_free_block] no free block --> zftl_garbage_collect()\n");
312 zftl_garbage_collect(zftl);
313 } while( --i !=0 );
314
315 return 1;
316 }
317
318
319void zftl_pack_tags(struct zftl_packed_tags *pt,
320 struct zftl_oob *t)
321{
322 memcpy((uint8_t *)&(pt->t),(uint8_t *)t,sizeof(struct zftl_oob));
323 zftl_ecc_calc_other((uint8_t *)&pt->t,
324 sizeof(struct zftl_oob),
325 &pt->ecc);
326
327}
328
329static uint32_t is_erased(uint8_t *buf, int len)
330{
331 int i = 0;
332 for (i = 0; i < len; i++)
333 if (buf[i] != 0xFF)
334 return 0;
335 return 1;
336}
337
338int zftl_unpack_tags(struct zftl_packed_tags *pt)
339{
340 enum zftl_ecc_result ecc_result = ZFTL_ECC_RESULT_NO_ERROR;
341 struct zftl_ecc_other ecc;
342 int result;
343
344
345 zftl_ecc_calc_other((unsigned char *)&pt->t,
346 sizeof(struct zftl_oob),
347 &ecc);
348 result = zftl_ecc_correct_other((unsigned char *)&pt->t,\
349 sizeof(struct zftl_oob),\
350 &pt->ecc, &ecc);
351 switch (result) {
352 case 0:
353 ecc_result = ZFTL_ECC_RESULT_NO_ERROR;
354 //printf("ZFTL_ECC_RESULT_NO_ERROR\n");
355 break;
356 case 1:
357
358 ecc_result = ZFTL_ECC_RESULT_FIXED;
359 printk("ZFTL_ECC_RESULT_FIXED\n");
360
361 break;
362 case -1:
363 if(!is_erased((unsigned char *)pt,sizeof(struct zftl_packed_tags)))
364 {
365 ecc_result = ZFTL_ECC_RESULT_UNFIXED;
366
367 //printk("ZFTL_ECC_RESULT_UNFIXED\n");
368 }
369
370 break;
371 default:
372 ecc_result = ZFTL_ECC_RESULT_UNKNOWN;
373 printk("ZFTL_ECC_RESULT_UNKNOWN\n");
374 }
375 if(ecc_result==ZFTL_ECC_RESULT_UNFIXED)
376 {
377
378 return -1;
379 }
380 else
381 {
382 return 0;
383 }
384}
385
386
387static int zftl_write_block(nand_info_t *nand, uint32_t offs, size_t *retlen,
388 struct zftl_oob *oob, u_char *buf)
389{
390 struct mtd_oob_ops ops;
391 int32_t res = 0;
392 uint32_t offset = offs;
393 size_t ret_len = 0;
394 size_t pagesize = nand->writesize;
395
396
397 #ifdef CONFIG_ZFTL_ENABLE_OOB_ECC
398 struct zftl_packed_tags pt;
399 zftl_pack_tags(&pt,oob);
400 #endif
401
402 /* write the remain */
403 res = nand->_write(nand, (loff_t)(offset + nand->writesize), nand->erasesize - pagesize,
404 &ret_len, (u_char *)(buf + pagesize) );
405
406 /* write the first page of the block write the oob */
407 ops.mode = MTD_OPS_AUTO_OOB;
408 ops.ooboffs = 0;
409
410 #ifdef CONFIG_ZFTL_ENABLE_OOB_ECC
411 ops.ooblen = sizeof(struct zftl_packed_tags);
412 ops.oobbuf = (uint8_t *)&pt;
413 #else
414 ops.ooblen = sizeof(struct zftl_oob);
415 ops.oobbuf = (uint8_t *)oob;
416 #endif
417 ops.datbuf = buf;
418 ops.len = pagesize;
419 res += nand->_write_oob(nand, (loff_t)offset, &ops);
420 *retlen = ops.retlen + ret_len;
421 return res;
422}
423
424
425
426int zftl_write(struct ZFTLrecord *zftl, uint32_t to, uint32_t len, u_char *buf)
427{
428 int ret = 0;
429 uint32_t offset_block_phy = 0;
430 uint32_t block_new = 0;
431 size_t retlen = 0;
432 u_char *buffer = buf;
433 struct zftl_oob *oob = (struct zftl_oob *)zftl->oobbuf;
434 uint32_t block_offset = 0;
435 uint32_t erasesize_shift = zftl->erasesize_shift;
436 uint32_t block_log = 0;
437 uint32_t erasesize = zftl->erasesize;
438 uint32_t is_upthreshold = 0;
439 uint32_t oob_size = zftl->oobsize;
440 uint32_t firstBlock = zftl->firstBlock;
441 u_char *blockbuf = zftl->blockbuf;
442
443 uint32_t left_to_write = len;
444 uint32_t write_length = 0;
445 uint32_t offset = to;
446
447 nand_info_t *nand = zftl->nand;
448
449 if((zftl == NULL) || (buf == NULL))
450 {
451 BUG();
452 }
453
454 while(left_to_write > 0)
455 {
456 /* ¿Õ¼ä£¬³õʼ»¯Îª 0xFF */
457 memset(blockbuf, 0xff, erasesize);
458 memset(oob, 0xff, oob_size);
459
460 /* »ñÈ¡Âß¼­¿é£¬¼°¿éÄÚÆ«ÒÆ */
461 block_log = offset >> (zftl->erasesize_shift);
462 block_offset = offset & (zftl->erasesize - 1); /* ¿éÄ򵀮«ÒƵØÖ· */
463
464 /* ÅжÏÂß¼­¿éÊÇ·ñÓÐÎïÀí¶ÔÓ¦¿é£¬Èç¹ûÓУ¬ÔòΪ¸ÄдÊý¾Ý£»Èç¹ûûÓУ¬ÔòΪµÚÒ»´Îд´Ë¿é */
465 if(zftl->blockRepTable[block_log] != BLOCK_NIL)
466 {
467 /* »ñÈ¡Âß¼­¿é¶ÔÓ¦µÄÎïÀí¿é */
468 offset_block_phy = zftl->blockRepTable[block_log];
469 zftl_debug(" [zftl_write] zftl->blockRepTable[%d] = %d\n", block_log, offset_block_phy);
470
471 /* Õû¸ö¶Áȡһ¿éÊý¾Ý */
472 zftl_debug(" [zftl_read] nand->read( -0x%0x-, -0x%0x-)\n",
473 ((firstBlock + offset_block_phy) << erasesize_shift),erasesize);
474 ret = nand->_read(nand, ((firstBlock + offset_block_phy) << erasesize_shift), erasesize, &retlen, blockbuf);
475 if (ret || retlen != erasesize)
476 {
477 printk(KERN_ERR"[zfltl]: -zftl_read- error\n");
478#ifdef CONFIG_MTD_NVRESUME
479 if((!zOss_NvInResume())&&(zftl==zftl_info[1])&&(zftl_res != 1))
480 {
481 return -1;
482 }
483#endif
484 }
485
486 /* ¶ÁÈ¡ÕâÒ»¿éµÄOOBÐÅÏ¢£¬²¢¸üРVERSION, Èç¹û´ïµ½°æ±¾ºÅµÄãÐÖµ£¬Ôò½øÐлØÊÕ */
487 if(zftl_read_oob(zftl, ((firstBlock + offset_block_phy) << erasesize_shift), (uint8_t *)oob ))
488 {
489 printk(" [zftl_write] read oob error at = 0x%x\n", (offset_block_phy << erasesize_shift));
490 //return -1;
491 }
492 if( oob->version == CONFIG_ZFLT_VERSION_THRESHOLD )
493 {
494 zftl_debug(" [zftl_write] up to the -CONFIG_ZFLT_VERSION_THRESHOLD-\n");
495 is_upthreshold = 1;
496 zftl_garbage_collect(zftl);
497 oob->version = 1;
498 }
499 else
500 {
501
502 oob->version += 1;
503 zftl_debug(" [zftl_write] oob->version = %d,oob->logicBlockID = %d\n", oob->version,oob->logicBlockID);
504 }
505
506 memcpy(oob->head, CONFIG_ZFLT_HEAD, CONFIG_ZFLT_HEAD_BYTE); /* ¿½±´zftlÍ· */
507 oob->logicBlockID = block_log;
508
509 /* Ìî³ä¸üРdata */
510 if (left_to_write < (erasesize - block_offset))
511 write_length = left_to_write;
512 else
513 write_length = nand->erasesize - block_offset;
514
515 memcpy(blockbuf + block_offset, buffer, write_length);
516 zftl_debug(" [zftl_write] update the date ( -0x%0x-, -0x%0x- )\n",
517 block_offset, write_length);
518
519
520 /* ѰÕÒÒ»¸ö FREE µÄÎïÀí¿é */
521 find_next_free_block_1:
522 if( zftl_find_free_block(zftl, &block_new) )/* BLOCK_USED */
523 {
524 /* ûÓÐÕÒµ½FREE¿é */
525 printk(" [zftl_write] there is enough block, please enlarge the partition\n");
526 return CAN_NOT_FIND_FREE_BLOCK;
527 }
528
529 /* дÈëÒ»¿é */
530 zftl_debug(" [zftl_write_block] nand->write( -0x%0x-, -0x%0x-)\n",
531 ((firstBlock + block_new) << erasesize_shift), erasesize);
532
533 if( zftl_write_block(nand, (loff_t)((firstBlock + block_new) << erasesize_shift), &retlen,
534 oob, blockbuf) )
535 {
536 /* дÊý¾Ýʧ°Üʱ£¬±ê¼ÇBBT£¬¸üРTABLE£¬ÖØÐ²éÕÒеĿéд */
537 printk(" -ERROR-\n");
538 zftl->blockTable[block_new] = BLOCK_BAD;
539 nand->_block_markbad(nand, (loff_t)((firstBlock + block_new) << erasesize_shift));
540 goto find_next_free_block_1;
541 }
542
543 /* ¸üРblockRepTable¡¢blockTable */
544 zftl->blockRepTable[oob->logicBlockID] = block_new;
545
546 zftl_debug(" [zftl_write] zftl->blockRepTable[oob->logicBlockID] = %d,oob->logicBlockID = %d\n", zftl->blockRepTable[oob->logicBlockID],oob->logicBlockID);
547
548 zftl->blockTable[block_new] = BLOCK_USED;
549 zftl->blockTable[offset_block_phy] = BLOCK_DIRTY;
550
551 /* ¸üРblockRepTable¡¢blockTable */
552 if( is_upthreshold == 1 )
553 {
554 zftl_debug(" [zftl_write] ( is_upthreshold == 1 )\n");
555 zftl_debug(" [zftl_write] eraseblock zftl->blockTable[-%d-]\n", offset_block_phy);
556 if( zftl_erase_block(nand, firstBlock + offset_block_phy) )
557 {
558 /* ²Á³ýʧ°Ü£¬±ê¼ÇΪ»µ¿ì */
559 zftl_debug(" [zftl_write] eraseblock zftl->blockTable[-%d-] ERROR!\n",
560 (firstBlock + offset_block_phy) << erasesize);
561 zftl->blockTable[offset_block_phy] = BLOCK_BAD;
562 nand->_block_markbad(nand, (loff_t)((firstBlock + offset_block_phy) << erasesize_shift)); /* ±ê¼Ç»µ¿é£¬¸üлµ¿é±í */
563 }
564 else
565 zftl->blockTable[offset_block_phy] = BLOCK_FREE;
566 }
567 zftl_debug("\n");
568
569 left_to_write -= write_length;
570 offset += write_length;
571 buffer += write_length;
572 }
573 else /* zftl->blockRepTable[block_log] == BLOCK_NIL */
574 {
575 /* ´ËÂß¼­µØÖ·µÚÒ»´Î±»Ð´ÈëÊý¾Ý */
576 zftl_debug(" [zftl_write] zftl->blockRepTable[%d] == BLOCK_NIL\n", block_log);
577
578 /* ²¢¸üÐÂOOB */
579 oob->logicBlockID = block_log;
580 oob->used = 0x1;
581 oob->version = 0x1;
582 memcpy(oob->head, CONFIG_ZFLT_HEAD, CONFIG_ZFLT_HEAD_BYTE); /* ¿½±´zftlÍ· */
583
584 /* Ìî³ä¸üРdata */
585 if (left_to_write < (erasesize - block_offset))
586 write_length = left_to_write;
587 else
588 write_length = nand->erasesize - block_offset;
589
590 memcpy(blockbuf + block_offset, buffer, write_length);
591 zftl_debug(" [zftl_write] update the date ( -0x%0x-, -0x%0x- )\n",
592 block_offset, write_length);
593
594 /* ѰÕÒÒ»¸ö FREE µÄÎïÀí¿é */
595 find_next_free_block_2:
596 if( zftl_find_free_block(zftl, &block_new) )
597 {
598 /* ûÓÐÕÒµ½FREE¿é */
599 printk(" [zftl_write] there is enough block, please enlarge the partition\n");
600 return CAN_NOT_FIND_FREE_BLOCK;
601 }
602
603 /* дÈëÒ»¿é */
604 zftl_debug(" [zftl_write_block] nand->write( -0x%0x-, -0x%0x-)\n",
605 ((firstBlock + block_new) << erasesize_shift), erasesize);
606
607 if( zftl_write_block(nand, (loff_t)((firstBlock + block_new) << erasesize_shift), &retlen,
608 oob, blockbuf) )
609 {
610 /* дÊý¾Ýʧ°Üʱ£¬±ê¼ÇBBT£¬¸üРTABLE£¬ÖØÐ²éÕÒеĿéд */
611 printk(" -ERROR-\n");
612 zftl->blockTable[block_new] = BLOCK_BAD;
613 nand->_block_markbad(nand, (loff_t)((firstBlock + block_new) << erasesize_shift));
614 goto find_next_free_block_2;
615 }
616
617 /* ¸üРblockRepTable¡¢blockTable */
618 zftl->blockRepTable[oob->logicBlockID] = block_new;
619
620 zftl_debug(" [zftl_write2] zftl->blockRepTable[oob->logicBlockID] = %d,oob->logicBlockID = %d\n", zftl->blockRepTable[oob->logicBlockID],oob->logicBlockID);
621
622 zftl->blockTable[block_new] = BLOCK_USED;
623
624 zftl_debug("\n");
625
626 left_to_write -= write_length;
627 offset += write_length;
628 buffer += write_length;
629 }
630
631 }
632
633 /* Added by zhouqi for xxx, 2014/04/23 */
634 zftl_garbage_collect(zftl);
635 zftl_debug("\n");
636
637 return 0;
638}
639
640
641int zftl_read(struct ZFTLrecord *zftl, uint32_t from, uint32_t len, u_char *buffer)
642{
643 int ret = 0;
644 uint32_t offset_block_phy;
645 uint32_t left_to_read = len;
646 uint32_t read_length = 0;
647 uint32_t retlen = 0;
648 u_char *buf = buffer;
649 uint32_t offset = from;
650 uint32_t block_offset = 0;
651 uint32_t block_log = 0;
652 uint32_t erasesize = zftl->erasesize;
653 uint32_t erasesize_shift = zftl->erasesize_shift;
654 nand_info_t *nand = zftl->nand;
655 uint32_t firstBlock = zftl->firstBlock;
656
657 if((zftl == NULL) || (buf == NULL))
658 {
659 BUG();
660 }
661
662 while( left_to_read > 0 )
663 {
664 block_offset = offset & (zftl->erasesize - 1);
665 block_log = offset >> zftl->erasesize_shift;
666
667 /* »ñÈ¡Âß¼­¿é¶ÔÓ¦µÄÎïÀí¿é */
668 if( zftl->blockRepTable[block_log] != BLOCK_NIL )
669 offset_block_phy = zftl->blockRepTable[block_log];
670 else
671 {
672 /* µ±Ã»ÓÐдÈëÊý¾Ýʱ£¬Ã»ÓÐÓ³Éä¹ØÏµ£¬¶ÁÈ¡Êý¾ÝȫΪ 0XFF */
673
674 if (left_to_read < (erasesize - block_offset))
675 read_length = left_to_read;
676 else
677 read_length = nand->erasesize - block_offset;
678
679 memset(buf, 0xff, read_length);
680
681 left_to_read -= read_length;
682 offset += read_length;
683 buf += read_length;
684
685 continue;
686
687 }
688
689 if (left_to_read < (erasesize - block_offset))
690 read_length = left_to_read;
691 else
692 read_length = nand->erasesize - block_offset;
693
694
695 zftl_debug(" [zftl_read] nand->read( -0x%0x-, -0x%0x-)\n",
696 ((firstBlock + offset_block_phy) << erasesize_shift) + block_offset,
697 read_length);
698 ret = nand->_read(nand, ((firstBlock + offset_block_phy) << erasesize_shift) + block_offset,
699 read_length, &retlen, buf);
700 if (ret || retlen != read_length)
701 {
702 printk(KERN_ERR"[zfltl]: -zftl_read- error\n");
703 //return -1;
704#ifdef CONFIG_MTD_NVRESUME
705 if((!zOss_NvInResume())&&(zftl==zftl_info[1])&&(zftl_res != 1))
706 {
707 return -1;
708 }
709#endif
710 }
711
712 left_to_read -= read_length;
713 offset += read_length;
714 buf += read_length;
715 }
716
717 zftl_debug("\n");
718 return 0;
719}
720
721
722struct ZFTLrecord * zftl_get_ZFTLrecord_byname(char* part_name)
723{
724 uint32_t i;
725
726 for(i = 0; zftl_partition_name[i] != NULL; i++ )
727 {
728 if(zftl_info[i]!=NULL)
729 {
730 if(strcmp(zftl_info[i]->mbd.mtd->name, part_name) == 0)
731 {
732 return zftl_info[i];
733 }
734 }
735
736 }
737 return NULL;
738}
739
740
741int zftl_init(unsigned char *part_name,struct ZFTLrecord *zftlinfo )
742{
743 nand_info_t *nand = mtd_fota;
744 //uint32_t i, j,k, block;
745 uint32_t k = 0;
746 struct ZFTLrecord *zftl = NULL;
747 uint32_t partition_size = 0;
748 uint32_t partition_offest = 0;
749 struct cmdline_mtd_partition *part;
750
751 printk( "zftl[%d] is %s\n",partnum,part_name);
752
753 /* ZFTLrecord½á¹¹ÌåÄÚ´æÉêÇë */
754 zftl_info[partnum] = zftlinfo;
755 if (!zftl_info[partnum])
756 {
757 printk( "zftl: out of memory for data structure ZFTLrecord\n");
758 return 1;
759 }
760 zftl = zftl_info[partnum];
761
762 zftl->nand = nand;
763 zftl->erasesize = nand->erasesize;
764 zftl->writesize = nand->writesize;
765 zftl->erasesize_shift = ffs(nand->erasesize) - 1;
766 zftl->writesize_shift = ffs(nand->writesize) - 1;
767 zftl->oobsize = nand->oobsize;
768
769 part = partitions;
770
771 for(k=0;k<part->num_parts;k++)
772 {
773 if ( strcmp( (char *)part->parts[k].name, part_name ) == 0 )
774 break;
775
776 } /* nvr */
777
778 partition_offest = part->parts[k].offset;
779 partition_size = part->parts[k].size;
780
781 if ( strcmp(part_name,"cdrom") == 0 )
782 {
783 cdrom_partsize = partition_size;
784 }
785
786 if ( strcmp(part_name,"nvro") == 0 )
787 {
788 nvro_partsize = partition_size;
789 printk("nvro_partsize=0x%0x\n",nvro_partsize);
790 }
791
792 if ( strcmp(part_name,"nvrwo") == 0 )
793 {
794 nvrwo_partsize = partition_size;
795 printk("nvrwo_partsize=0x%0x\n",nvrwo_partsize);
796 }
797
798 zftl->firstBlock= partition_offest >> zftl->erasesize_shift; /* ¾ßÌåµÄÊýÖµ´Ó·ÖÇøÖлñµÃ */
799 zftl->numBlocks = partition_size / zftl->erasesize; /* ÔõôȷÈÏÇøÓò·¶Î§ zhouqi,ʵ¼ÊʹÓÃʱ¿éºÅÒª -1 ?*/
800
801 /* ¿é»º´æÉêÇë */
802 zftl->blockbuf = kmalloc(zftl->erasesize, GFP_KERNEL);
803 if (!zftl->blockbuf)
804 {
805 printk( "zftl: out of memory for data structure blockbuf\n");
806 goto failed_alloc_blockbuf;
807 }
808
809 /* OOB»º´æÉêÇë */
810 zftl->oobbuf = kmalloc(zftl->oobsize, GFP_KERNEL);
811 if (!zftl->oobbuf)
812 {
813 printk( "zftl: out of memory for data oobbuf\n");
814 goto failed_alloc_oobbuf;
815 }
816
817 /* blockRepTable±íÄÚ´æÉêÇë, ³õʼ»¯Îª 0xFFFF*/
818 zftl->blockRepTable = kmalloc(zftl->numBlocks * sizeof(zftl->blockRepTable), GFP_KERNEL);
819 if (!zftl->blockRepTable)
820 {
821 printk( "zftl: out of memory for data structure blockRepTable\n");
822 goto failed_alloc_blockreptable;
823 }
824 memset(zftl->blockRepTable, 0xff, zftl->numBlocks * sizeof(zftl->blockRepTable));
825
826 /* versionTable±íÄÚ´æÉêÇë */
827 /* ³õʼ»¯Îª¶¼Îª0£¬NANDÖеÄÊý¾Ýversion×îСΪ 1 */
828 zftl->versionTable = kzalloc(zftl->numBlocks * sizeof(zftl->versionTable), GFP_KERNEL);
829 if (!zftl->versionTable)
830 {
831 printk( "zftl: out of memory for data structure versionTable\n");
832 goto failed_alloc_versionTable;
833 }
834
835 /* blockTable±íÄÚ´æÉêÇë */
836 zftl->blockTable = kzalloc(zftl->numBlocks * sizeof(zftl->blockTable), GFP_KERNEL);
837 if (!zftl->blockTable)
838 {
839 printk( "zftl: out of memory for data structure blockTable\n");
840 goto failed_alloc_blocktable;
841 }
842
843 /* ·ÖÎö¹ÒÔØzftl·ÖÇø£¬½¨Á¢ÄÚ´æ±í */
844 if ( zftl_setup_table((zftl), &zftl->is_writed))
845 {
846 printk( "zftl: could not mount device\n");
847 goto failed_setup_table;
848 }
849
850 zftl_debug(" [zftl_init] is_writed[%d] = %d\n", partnum, zftl->is_writed);
851 partnum++;
852 if(!mutex_inited)
853 {
854 mutex_init(&zftl_mutex);
855 mutex_inited = 1;
856 }
857 return 0;
858
859failed_setup_table:
860 kfree(zftl->blockTable);
861failed_alloc_blocktable:
862 kfree(zftl->versionTable);
863failed_alloc_versionTable:
864 kfree(zftl->blockRepTable);
865failed_alloc_blockreptable:
866 kfree(zftl->oobbuf);
867failed_alloc_oobbuf:
868 kfree(zftl->blockbuf);
869failed_alloc_blockbuf:
870 kfree(zftl);
871 return 1;
872}
873
874static void zftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
875{
876 uint32_t i;
877 struct ZFTLrecord *zftl = NULL;
878
879 for(i=0; zftl_partition_name[i] != NULL; i++)
880 {
881
882 if(strcmp(mtd->name, zftl_partition_name[i]) == 0)
883 {
884
885 break;
886 }
887 }
888
889 if(zftl_partition_name[i] == NULL)
890 {
891 return;
892 }
893
894 zftl = kzalloc(sizeof(struct ZFTLrecord), GFP_KERNEL);
895 if (!zftl)
896 {
897 kfree(zftl);
898 return;
899 }
900 zftl->mbd.mtd = mtd;
901 zftl->mbd.devnum = mtd->index;
902 zftl->mbd.tr = tr;
903 zftl->mbd.size = mtd->size >> 12;
904
905 zftl_init(mtd->name,zftl);
906
907 if (add_mtd_blktrans_dev(&zftl->mbd))
908 {
909 kfree(zftl);
910 }
911
912 return;
913}
914static void zftl_remove_dev(struct mtd_blktrans_dev *dev)
915{
916 del_mtd_blktrans_dev(dev);
917}
918static int zftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
919 char *buffer)
920{
921 struct ZFTLrecord *zftl = NULL;
922 int ret = 0;
923
924 mutex_lock(&zftl_mutex);
925
926 zftl = zftl_get_ZFTLrecord_byname(mbd->mtd->name);
927 if(!zftl)
928 {
929 mutex_unlock(&zftl_mutex);
930 return -2;
931 }
932 ret = zftl_read(zftl, block<<12, (uint32_t)4096, (u_char *)buffer);
933 mutex_unlock(&zftl_mutex);
934 return ret;
935}
936
937static int zftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
938 char *buffer)
939{
940 struct ZFTLrecord *zftl = NULL;
941 int ret = 0;
942
943 mutex_lock(&zftl_mutex);
944
945 zftl = zftl_get_ZFTLrecord_byname(mbd->mtd->name);
946 if(!zftl)
947 {
948 mutex_unlock(&zftl_mutex);
949 return -2;
950 }
951 ret = zftl_write(zftl, block<<12, (uint32_t)4096, (u_char *)buffer);
952 mutex_unlock(&zftl_mutex);
953 return ret;
954}
955
956int zftl_wrapper_write(char *part_name, int dwStart, int dwLen, char* from)
957{
958 int ret = 0;
959 struct ZFTLrecord *zftl = NULL;
960
961 mutex_lock(&zftl_mutex);
962
963 if((part_name == NULL) || (from == NULL))
964 {
965 mutex_unlock(&zftl_mutex);
966 return -5;
967 }
968
969 zftl = zftl_get_ZFTLrecord_byname(part_name);
970 if(zftl == NULL)
971 {
972 BUG();
973 mutex_unlock(&zftl_mutex);
974 return -1; //×ö¶ÏÑÔ
975 }
976
977 ret = zftl_write(zftl, dwStart, dwLen, from);
978 if(ret != 0)
979 {
980 mutex_unlock(&zftl_mutex);
981 return ret;
982 }
983
984 mutex_unlock(&zftl_mutex);
985
986 return 0;
987}
988EXPORT_SYMBOL_GPL(zftl_wrapper_write);
989
990int zftl_wrapper_read(char *part_name, int dwStart, int dwLen, char* to)
991{
992 int ret = 0;
993 struct ZFTLrecord *zftl = NULL;
994
995 mutex_lock(&zftl_mutex);
996
997 if((part_name == NULL) || (to == NULL))
998 {
999 mutex_unlock(&zftl_mutex);
1000 return -5;
1001 }
1002
1003 zftl = zftl_get_ZFTLrecord_byname(part_name);
1004 if(zftl == NULL)
1005
1006 {
1007 BUG();
1008 mutex_unlock(&zftl_mutex);
1009 return -1; //×ö¶ÏÑÔ
1010 }
1011
1012 ret = zftl_read(zftl, dwStart, dwLen, to);
1013 if(ret != 0)
1014 {
1015 mutex_unlock(&zftl_mutex);
1016 return ret;
1017 }
1018
1019 mutex_unlock(&zftl_mutex);
1020 return 0;
1021}
1022EXPORT_SYMBOL_GPL(zftl_wrapper_read);
1023
1024int nand_NvRead(int dwStart, int dwLen, char* to)
1025{
1026 mutex_lock(&zftl_mutex);
1027 struct ZFTLrecord *zftl = NULL;
1028 int ret = 0;
1029
1030 if( dwStart < nvro_partsize )
1031 {
1032 zftl = zftl_get_ZFTLrecord_byname("nvro"); /*NVR,0~1M*/
1033 }
1034 else if( dwStart < nvro_partsize + nvrwo_partsize)
1035 {
1036 zftl = zftl_get_ZFTLrecord_byname("nvrwo"); /*NVR,0~1M*/
1037 dwStart -= nvro_partsize;
1038 }
1039 else
1040 {
1041 zftl = zftl_get_ZFTLrecord_byname("nvrw"); /* NVRW, 1~5M*/
1042 dwStart = dwStart - nvro_partsize - nvrwo_partsize;
1043 }
1044 if(!zftl)
1045 {
1046 mutex_unlock(&zftl_mutex);
1047 return -2;
1048 }
1049 ret = zftl_read(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)to);
1050 mutex_unlock(&zftl_mutex);
1051
1052 return ret;
1053
1054}
1055EXPORT_SYMBOL_GPL(nand_NvRead);
1056
1057int nand_NvProgram(int dwStart, int dwLen, char* from)
1058{
1059 mutex_lock(&zftl_mutex);
1060 struct ZFTLrecord *zftl = NULL;
1061 int ret = 0;
1062
1063 if( dwStart < nvro_partsize )
1064 {
1065 zftl = zftl_get_ZFTLrecord_byname("nvro"); /*NVR,0~1M*/
1066 }
1067 else if( dwStart < nvro_partsize + nvrwo_partsize)
1068 {
1069 zftl = zftl_get_ZFTLrecord_byname("nvrwo"); /*NVR,0~1M*/
1070 dwStart -= nvro_partsize;
1071 }
1072 else
1073 {
1074 zftl = zftl_get_ZFTLrecord_byname("nvrw"); /* NVRW, 1~5M*/
1075 dwStart = dwStart - nvro_partsize - nvrwo_partsize;
1076 }
1077 if(!zftl)
1078 {
1079 mutex_unlock(&zftl_mutex);
1080 return -2;
1081 }
1082 ret = zftl_write(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)from);
1083 mutex_unlock(&zftl_mutex);
1084 return ret;
1085}
1086EXPORT_SYMBOL_GPL(nand_NvProgram);
1087
1088int nand_CdromRead(void *devData,void *buffer, uint32_t blkcnt, uint32_t pos )
1089{
1090 mutex_lock(&zftl_mutex);
1091 struct ZFTLrecord *zftl = NULL;
1092 int ret = 0;
1093
1094 zftl = zftl_get_ZFTLrecord_byname("cdrom");
1095 if(!zftl)
1096 {
1097 mutex_unlock(&zftl_mutex);
1098 return -2;
1099 }
1100 ret = zftl_read(zftl, (pos<<9), (uint32_t)(blkcnt<<9), (u_char *)buffer);
1101 if(ret == 0)
1102 {
1103 ret = blkcnt;
1104 }
1105 mutex_unlock(&zftl_mutex);
1106 return ret;
1107
1108}
1109EXPORT_SYMBOL_GPL(nand_CdromRead);
1110
1111int nand_CdromProgram(void *devData,void *buffer, uint32_t blkcnt, uint32_t pos)
1112{
1113 mutex_lock(&zftl_mutex);
1114 struct ZFTLrecord *zftl = NULL;
1115 int ret = 0;
1116
1117 zftl = zftl_get_ZFTLrecord_byname("cdrom");
1118 if(!zftl)
1119 {
1120 mutex_unlock(&zftl_mutex);
1121 return -2;
1122 }
1123 ret = zftl_write(zftl, (pos<<9), (uint32_t)(blkcnt<<9), (u_char *)buffer);
1124
1125 if(ret == 0)
1126 {
1127 ret = blkcnt;
1128 }
1129 mutex_unlock(&zftl_mutex);
1130 return ret;
1131}
1132EXPORT_SYMBOL_GPL(nand_CdromProgram);
1133int nand_SmsRead(int dwStart, int dwLen, char* to)
1134{
1135 mutex_lock(&zftl_mutex);
1136 struct ZFTLrecord *zftl = NULL;
1137 int ret = 0;
1138
1139 zftl = zftl_get_ZFTLrecord_byname("sms");
1140 if(!zftl)
1141 {
1142 mutex_unlock(&zftl_mutex);
1143 return -2;
1144 }
1145 ret = zftl_read(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)to);
1146 mutex_unlock(&zftl_mutex);
1147 return ret;
1148
1149}
1150EXPORT_SYMBOL_GPL(nand_SmsRead);
1151
1152int nand_SmsProgram(int dwStart, int dwLen, char* from)
1153{
1154 mutex_lock(&zftl_mutex);
1155 struct ZFTLrecord *zftl = NULL;
1156 int ret = 0;
1157
1158 zftl = zftl_get_ZFTLrecord_byname("sms");
1159 if(!zftl)
1160 {
1161 mutex_unlock(&zftl_mutex);
1162 return -2;
1163 }
1164 ret = zftl_write(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)from);
1165 mutex_unlock(&zftl_mutex);
1166 return ret;
1167}
1168EXPORT_SYMBOL_GPL(nand_SmsProgram);
1169
1170int nand_ResetFlagProgram(int dwStart, int dwLen, char* from)
1171{
1172 mutex_lock(&zftl_mutex);
1173 struct ZFTLrecord *zftl = NULL;
1174 int ret = 0;
1175
1176
1177 //zftl = zftl_info[2]; /* fotaflag */
1178 zftl = zftl_get_ZFTLrecord_byname("fotaflag");
1179 if(!zftl)
1180 {
1181 mutex_unlock(&zftl_mutex);
1182 return -2;
1183 }
1184 ret = zftl_write(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)from);
1185 mutex_unlock(&zftl_mutex);
1186
1187 return ret;
1188}
1189EXPORT_SYMBOL_GPL(nand_ResetFlagProgram);
1190
1191static struct mtd_blktrans_ops zftl_tr = {
1192 .name = "zftl",
1193 .major = 35,
1194 .part_bits = 0,
1195 .blksize = 4096,
1196 .readsect = zftl_readblock,
1197 .writesect = zftl_writeblock,
1198 .add_mtd = zftl_add_mtd,
1199 .remove_dev = zftl_remove_dev,
1200 .owner = THIS_MODULE,
1201};
1202
1203static int __init init_zftl(void)
1204{
1205 return register_mtd_blktrans(&zftl_tr);
1206}
1207
1208static void __exit cleanup_zftl(void)
1209{
1210 deregister_mtd_blktrans(&zftl_tr);
1211}
1212
1213module_init(init_zftl);
1214module_exit(cleanup_zftl);
1215
1216MODULE_LICENSE("GPL");
1217MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
1218MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");
1219
1220
1221
1222
1223
1224
1225