📄 nftl.c
字号:
#endif /* CONFIG_NFTL_RW */static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer){ u16 lastgoodEUN; u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)]; unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); unsigned int status; int silly = MAX_LOOPS; size_t retlen; struct nftl_bci bci; lastgoodEUN = BLOCK_NIL; if (thisEUN != BLOCK_NIL) { while (thisEUN < nftl->nb_blocks) { if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci) < 0) status = SECTOR_IGNORE; else status = bci.Status | bci.Status1; switch (status) { case SECTOR_FREE: /* no modification of a sector should follow a free sector */ goto the_end; case SECTOR_DELETED: lastgoodEUN = BLOCK_NIL; break; case SECTOR_USED: lastgoodEUN = thisEUN; break; case SECTOR_IGNORE: break; default: printk("Unknown status for block %d in EUN %d: %x\n", block, thisEUN, status); break; } if (!silly--) { printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", block / (nftl->EraseSize / 512)); return 1; } thisEUN = nftl->ReplUnitTable[thisEUN]; } } the_end: if (lastgoodEUN == BLOCK_NIL) { /* the requested block is not on the media, return all 0x00 */ memset(buffer, 0, 512); } else { loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs; size_t retlen; u_char eccbuf[6]; if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf)) return -EIO; } return 0;}static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){ struct NFTLrecord *nftl; nftl = NFTLs[MINOR(inode->i_rdev) / 16]; if (!nftl) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; g.heads = nftl->heads; g.sectors = nftl->sectors; g.cylinders = nftl->cylinders; g.start = part_table[MINOR(inode->i_rdev)].start_sect; return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; } case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; return put_user(part_table[MINOR(inode->i_rdev)].nr_sects, (long *) arg); case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); if (nftl->mtd->sync) nftl->mtd->sync(nftl->mtd); return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (nftl->usecount > 1) return -EBUSY;#if LINUX_VERSION_CODE < 0x20328 resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) / 16);#else grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) / 16, 1<<4, nftl->nr_sects);#endif return 0;#if (LINUX_VERSION_CODE < 0x20303) RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */#else case BLKROSET: case BLKROGET: case BLKSSZGET: return blk_ioctl(inode->i_rdev, cmd, arg);#endif default: return -EINVAL; }}void nftl_request(RQFUNC_ARG){ unsigned int dev, block, nsect; struct NFTLrecord *nftl; char *buffer; struct request *req; int res; while (1) { INIT_REQUEST; /* blk.h */ req = CURRENT; /* We can do this because the generic code knows not to touch the request at the head of the queue */ spin_unlock_irq(&io_request_lock); DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n"); DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n", (req->cmd == READ) ? "Read " : "Write", req->sector, req->current_nr_sectors); dev = MINOR(req->rq_dev); block = req->sector; nsect = req->current_nr_sectors; buffer = req->buffer; res = 1; /* succeed */ if (dev >= MAX_NFTLS * 16) { /* there is no such partition */ printk("nftl: bad minor number: device = %s\n", kdevname(req->rq_dev)); res = 0; /* fail */ goto repeat; } nftl = NFTLs[dev / 16]; DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n"); down(&nftl->mutex); DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n"); if (block + nsect > part_table[dev].nr_sects) { /* access past the end of device */ printk("nftl%c%d: bad access: block = %d, count = %d\n", (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect); up(&nftl->mutex); res = 0; /* fail */ goto repeat; } block += part_table[dev].start_sect; if (req->cmd == READ) { DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x " "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors); for ( ; nsect > 0; nsect-- , block++, buffer += 512) { /* Read a single sector to req->buffer + (512 * i) */ if (NFTL_readblock(nftl, block, buffer)) { DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n"); up(&nftl->mutex); res = 0; goto repeat; } } DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n"); up(&nftl->mutex); goto repeat; } else if (req->cmd == WRITE) { DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x " "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);#ifdef CONFIG_NFTL_RW for ( ; nsect > 0; nsect-- , block++, buffer += 512) { /* Read a single sector to req->buffer + (512 * i) */ if (NFTL_writeblock(nftl, block, buffer)) { DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n"); up(&nftl->mutex); res = 0; goto repeat; } } DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");#else res = 0; /* Writes always fail */#endif /* CONFIG_NFTL_RW */ up(&nftl->mutex); goto repeat; } else { DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n"); up(&nftl->mutex); res = 0; goto repeat; } repeat: DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res); spin_lock_irq(&io_request_lock); end_request(res); }}static int nftl_open(struct inode *ip, struct file *fp){ int nftlnum = MINOR(ip->i_rdev) / 16; struct NFTLrecord *thisNFTL; thisNFTL = NFTLs[nftlnum]; DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");#ifdef CONFIG_KMOD if (!thisNFTL && nftlnum == 0) { request_module("docprobe"); thisNFTL = NFTLs[nftlnum]; }#endif if (!thisNFTL) { DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", nftlnum, ip->i_rdev, ip, fp); return -ENODEV; }#ifndef CONFIG_NFTL_RW if (fp->f_mode & FMODE_WRITE) return -EROFS;#endif /* !CONFIG_NFTL_RW */ thisNFTL->usecount++; MOD_INC_USE_COUNT; if (!get_mtd_device(thisNFTL->mtd, -1)) { MOD_DEC_USE_COUNT; return /* -E'SBUGGEREDOFF */ -ENXIO; } return 0;}static int nftl_release(struct inode *inode, struct file *fp){ struct super_block *sb = get_super(inode->i_rdev); struct NFTLrecord *thisNFTL; thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16]; DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); fsync_dev(inode->i_rdev); if (sb) invalidate_inodes(sb); invalidate_buffers(inode->i_rdev); if (thisNFTL->mtd->sync) thisNFTL->mtd->sync(thisNFTL->mtd); thisNFTL->usecount--; MOD_DEC_USE_COUNT; put_mtd_device(thisNFTL->mtd); return 0;}#if LINUX_VERSION_CODE < 0x20326static struct file_operations nftl_fops = { read: block_read, write: block_write, ioctl: nftl_ioctl, open: nftl_open, release: nftl_release, fsync: block_fsync,};#elsestatic struct block_device_operations nftl_fops = { open: nftl_open, release: nftl_release, ioctl: nftl_ioctl};#endif/**************************************************************************** * * Module stuff * ****************************************************************************/#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)#define init_nftl init_module#define cleanup_nftl cleanup_module#endifstatic struct mtd_notifier nftl_notifier = {NFTL_notify_add, NFTL_notify_remove, NULL};/* static int __init init_nftl(void) */int __init init_nftl(void){ int i; printk(KERN_NOTICE "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n");#ifdef PRERELEASE printk(KERN_INFO"$Id: nftl.c,v 1.57 2000/12/01 17:51:54 dwmw2 Exp $\n");#endif if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){ printk("unable to register NFTL block device on major %d\n", MAJOR_NR); return -EBUSY; } else {#if LINUX_VERSION_CODE < 0x20320 blk_dev[MAJOR_NR].request_fn = nftl_request;#else blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);#endif /* set block size to 1kB each */ for (i = 0; i < 256; i++) { nftl_blocksizes[i] = 1024; } blksize_size[MAJOR_NR] = nftl_blocksizes; nftl_gendisk.next = gendisk_head; gendisk_head = &nftl_gendisk; } register_mtd_user(&nftl_notifier); return 0;}static void __exit cleanup_nftl(void){ struct gendisk *gd, **gdp; unregister_mtd_user(&nftl_notifier); unregister_blkdev(MAJOR_NR, "nftl"); #if LINUX_VERSION_CODE < 0x20320 blk_dev[MAJOR_NR].request_fn = 0;#else blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));#endif /* remove ourself from generic harddisk list FIXME: why can't I found this partition on /proc/partition */ for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) if (*gdp == &nftl_gendisk) { gd = *gdp; *gdp = gd->next; break; }}module_init(init_nftl);module_exit(cleanup_nftl);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -