📄 ssfdc.c
字号:
ssfdc_cached = 0xFFFFFFFF; memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch)); new = ssfdc_allocate_new(pt_smcpart, zone); PDEBUG("ssfdc_write : zone %d, block %d, lbn %d, physical 0x%x, unallocated, new 0x%x\n", zone, block, sector, physical, new); } if(new != -1) { memcpy(&ssfdc_scratch[(offset * SECTOR_SIZE)], ptr, size); PDEBUG("ssfdc_write : new 0x%x, offset 0x%x, size 0x%x, block 0x%x\n", new, offset, size, block); for(sc=0; sc<SECTORS_PER_BLOCK; sc++) { memset(ssfdc_buffer, 0xFF, OOB_SIZE); nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]); nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]); for(i=0; i<6; i++) ssfdc_buffer[ssfdc_ecc[i]] = ecc_calc[i]; i = (block << 1) | 0x1000; i |= ssfdc_parity(block); ssfdc_buffer[7] = ssfdc_buffer[12] = i & 0xFF; ssfdc_buffer[6] = ssfdc_buffer[11] = (i & 0xFF00) >> 0x08; memcpy(&ssfdc_oob_buf[sc * OOB_SIZE], ssfdc_buffer, OOB_SIZE); } pt_smcpart->mtd->write_ecc(pt_smcpart->mtd, new, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch, ssfdc_oob_buf, &ssfdc_ffoob_info); if(retlen != SMC_BLOCK_SIZE) { printk(KERN_WARNING "ssfdc_write : failed to write block, physical 0x%x, returned 0x%x\n", new, retlen); return -ENXIO; } /* change the mapping table to reflect the new block placement */ *(pt_logical + block) = (new % ZONE_SIZE) / SMC_BLOCK_SIZE; PDEBUG("ssfdc_write : logical 0x%x + 0x%x = 0x%x\n", (unsigned int)pt_logical, block, (new % ZONE_SIZE) / SMC_BLOCK_SIZE); *(pt_physical + ((new % ZONE_SIZE) / SMC_BLOCK_SIZE)) = block; PDEBUG("ssfdc_write : physical 0x%x + 0x%x = 0x%x\n", (unsigned int)pt_physical, ((new % ZONE_SIZE) / SMC_BLOCK_SIZE), block); ssfdc_cached = new; } ptr += size; ptr_done = 0; sectors_written += (size / SECTOR_SIZE); if(do_erase) ssfdc_erase(pt_smcpart, physical); } return(0);}static int ssfdc_sector_blank(partition_t * pt_smcpart, int sc) {int b; for(b=0; b<SECTOR_SIZE; b++) { if(ssfdc_scratch[b + (sc * SECTOR_SIZE)] != 0xFF) return(0); } for(b=0; b<OOB_SIZE; b++) { if((b==6) || (b==7) || (b==11) || (b==12)) continue; // Block address fields if(ssfdc_buffer[b] != 0xFF) return(0); } return(1);}static int ssfdc_allocate_new(partition_t * pt_smcpart, int zone) { int new = pt_smcpart->last_written[zone] + 1; int * pt_physical; int physical; int block; int retlen; unsigned char oob[16]; if(new >= BLOCKS_PER_ZONE) new = 0; while (new != pt_smcpart->last_written[zone]) { block = new % BLOCKS_PER_ZONE; pt_physical = pt_smcpart->zone + (zone * 2048) + 1024 + block; physical = (zone * ZONE_SIZE) + (block * SMC_BLOCK_SIZE); PDEBUG("ssfdc_allocate_new : zone %d, block %d, address 0x%08x, data 0x%08x\n", zone, block, (unsigned int)pt_physical, *pt_physical); if(*pt_physical == 0xFFFFFFFF) { PDEBUG("ssfdc_allocate_new : physical 0x%x = 0x%x\n", (unsigned int)pt_physical, *pt_physical); memset(oob, 0, OOB_SIZE); pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical, OOB_SIZE, &retlen, oob); if((oob[5] == 0xFF) && (retlen == OOB_SIZE)) { // If not a bad block pt_smcpart->last_written[zone] = new; return((new * SMC_BLOCK_SIZE) + (zone * ZONE_SIZE)); } else { PDEBUG("ssfdc_allocate_new : new 0x%x, physical 0x%x, block status 0x%x, oob length 0x%x\n", new, physical, oob[5], retlen); } } new++; if(new >= BLOCKS_PER_ZONE) new = 0; } panic("ssfdc_allocate_new : cant find free block\n");} static int ssfdc_read(partition_t *pt_smcpart, caddr_t buffer, u_long sector, u_long nblocks){ int zone, block, offset; int sectors_read = 0; int physical; int size; int retlen; int i; int sc; unsigned char * ptr = (unsigned char *)buffer; unsigned char ecc_code[6], ecc_calc[6];/* unsigned char smc_status; smc_status = in_8((void *)&pt_ssfdc_smc->smc_status); if(!(smc_status & SMC_PRESENT)) { printk("ssfdc : media not present\n"); return -ENXIO; } if(smc_status & SMC_CHANGED) { out_8((void *)&pt_ssfdc_smc->smc_status, smc_status); ssfdc_read_partitions(pt_smcpart); printk("ssfdc : media change\n"); }*/ while(sectors_read < nblocks) { zone = (sector + sectors_read) / SECTORS_PER_ZONE; block = ((sector + sectors_read) % SECTORS_PER_ZONE) / SECTORS_PER_BLOCK ; offset = ((sector + sectors_read) % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ; if(offset) { size = ((SECTORS_PER_BLOCK - offset) < (nblocks - sectors_read)) ? (SECTORS_PER_BLOCK - offset) : (nblocks - sectors_read); } else { size = (SECTORS_PER_BLOCK < (nblocks - sectors_read)) ? SECTORS_PER_BLOCK : nblocks - sectors_read; } size *= SECTOR_SIZE; PDEBUG("ssfdc_read : device %d, sector %d, count %d, zone %d, block %d, offset %d, done %d, size %d, address 0x%x\n", pt_smcpart->count, sector, nblocks, zone, block, offset, sectors_read, size, (unsigned int)ptr); physical = ssfdc_physical(pt_smcpart, zone, block); if(physical >= 0) { if(ssfdc_cached != physical) { pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, physical, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch, ssfdc_oob_buf, &ssfdc_ffoob_info); if(retlen != SMC_BLOCK_SIZE) { printk(KERN_WARNING "ssfdc_read : failed to read physical\n"); return -ENXIO; } for(sc=0; sc<SECTORS_PER_BLOCK; sc++) { pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), sizeof(ssfdc_buffer), &retlen, ssfdc_buffer); if(retlen != sizeof(ssfdc_buffer)) { printk(KERN_WARNING "ssfdc_read : failed to read physical oob\n"); return -ENXIO; } nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]); nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]); for(i=0; i<3; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]]; for(i=3; i<6; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]]; nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_code[0], &ecc_calc[0]); nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_code[3], &ecc_calc[3]); } /* Get the ecc bytes and check that they are ok */ } ssfdc_cached = physical; } else { memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch)); ssfdc_cached = 0xFFFFFFFF; } memcpy(ptr, &ssfdc_scratch[(offset * SECTOR_SIZE)], size); ptr += size; sectors_read += (size / SECTOR_SIZE); } return(0);}static void ssfdc_erase_callback(struct erase_info *erase) { PDEBUG("ssfdc_erase_callback : wake erase\n"); up(&ssfdc_semaphore); PDEBUG("ssfdc_erase_callback : woken erase\n");}static int ssfdc_erase(partition_t *pt_smcpart, unsigned int offset){ int ret = 0; struct erase_info *erase; unsigned char * junk; unsigned char * oob; int retlen; int b, sc; PDEBUG("ssfdc_erase : offset 0x%08x\n", offset); erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL); junk=kmalloc(pt_smcpart->mtd->erasesize + 16, GFP_KERNEL); oob = junk + pt_smcpart->mtd->erasesize; if (!erase) return -ENOMEM; if (!junk) return -ENOMEM; erase->addr = offset; erase->len = pt_smcpart->mtd->erasesize; erase->callback = ssfdc_erase_callback; ret = pt_smcpart->mtd->erase(pt_smcpart->mtd, erase); if(ret) { printk(KERN_WARNING "ssfdc_erase : failed status 0x%x\n", ret); goto end; } down(&ssfdc_semaphore); pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, offset, SMC_BLOCK_SIZE, &retlen, junk, ssfdc_oob_buf, &ssfdc_ffoob_info); if(retlen != SMC_BLOCK_SIZE) { printk(KERN_WARNING "ssfdc_erase : offset 0x%x, read returned length %d\n", offset, retlen); goto end; } for(sc=0; sc < SECTORS_PER_BLOCK; sc++) { for(b=0; b<SECTOR_SIZE; b++) { if(*(junk + (b + (sc * SECTOR_SIZE))) != 0xFF) { printk(KERN_WARNING "ssfdc_erase : offset 0x%x, sector 0x%x, byte 0x%x, data 0x%02x, expected 0xff\n" , offset, sc, b, *(junk + (b + (sc * SECTOR_SIZE)))); goto end; } } pt_smcpart->mtd->read_oob(pt_smcpart->mtd, offset + (sc * SECTOR_SIZE), OOB_SIZE, &retlen, oob); if(retlen != OOB_SIZE) { printk(KERN_WARNING "ssfdc_erase : offset 0x%x, read oob returned length %d\n", offset, retlen); goto end; } for(b=0; b<OOB_SIZE; b++) { if(*(oob+b) != 0xFF) { printk(KERN_WARNING "ssfdc_erase : offset 0x%x, byte 0x%x, oob got 0x%02x, expected 0xff\n", offset, b, *(oob+b)); goto end; } } }end: kfree(erase); kfree(junk); return ret;} /* erase_xfer */int init_ssfdc(void){ int result, i;// unsigned char smc_status;// #define B01159_FIO_PBASE 0x0000000148000000 /* Physical Base address of SMC control chip */ printk(KERN_INFO "SSFDC block device translation layer V1.0\n");/* pt_ssfdc_smc = ioremap64(B01159_FIO_PBASE, 1024); if(!pt_ssfdc_smc){ printk("ssfdc : failed to map SMC control device\n"); return(-EFAULT); } smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);*/ memset(ssfdc_ffoob_buf, 0xFF, sizeof(ssfdc_ffoob_buf)); for (i = 0; i < MAX_DEVICES*MAX_PARTITIONS; i++) { ssfdc_hd[i].nr_sects = 0; ssfdc_hd[i].start_sect = 0; ssfdc_blocksizes[i] = 4096; } blksize_size[SSFDC_MAJOR] = ssfdc_blocksizes; ssfdc_gendisk.major = SSFDC_MAJOR; memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch)); result = register_blkdev(ssfdc_major, "ssfdc", &ssfdc_fops); if(result != 0) { printk(KERN_WARNING "ssfdc : failed to get a major number\n"); return(result); }// if(ssfdc_major == 0) ssfdc_major = result; blk_init_queue(BLK_DEFAULT_QUEUE(ssfdc_major), &do_ssfdc_request); add_gendisk(&ssfdc_gendisk); register_mtd_user(&ssfdc_notifier); init_MUTEX_LOCKED(&ssfdc_semaphore); return 0;}static void __exit cleanup_ssfdc(void){ int i; for(i=0; i<MAX_DEVICES; i++) { if(SMCParts[i].zone)kfree(SMCParts[i].zone); } unregister_mtd_user(&ssfdc_notifier); unregister_blkdev(ssfdc_major, "ssfdc"); blk_cleanup_queue(BLK_DEFAULT_QUEUE(ssfdc_major)); blksize_size[SSFDC_MAJOR] = NULL; del_gendisk(&ssfdc_gendisk);}module_init(init_ssfdc);module_exit(cleanup_ssfdc);MODULE_LICENSE("GPL");MODULE_AUTHOR("Simon Haynes <simon@baydel.com>");MODULE_DESCRIPTION("SSFDC translation layer support for MTD");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -