File: /usr/src/linux/drivers/mtd/mtdblock.c

1     /* 
2      * Direct MTD block device access
3      *
4      * $Id: mtdblock.c,v 1.38 2000/11/27 08:50:22 dwmw2 Exp $
5      *
6      * 02-nov-2000	Nicolas Pitre		Added read-modify-write with cache
7      */
8     
9     #include <linux/config.h>
10     #include <linux/types.h>
11     #include <linux/module.h>
12     #include <linux/kernel.h>
13     #include <linux/slab.h>
14     #include <linux/mtd/mtd.h>
15     
16     #define MAJOR_NR MTD_BLOCK_MAJOR
17     #define DEVICE_NAME "mtdblock"
18     #define DEVICE_REQUEST mtdblock_request
19     #define DEVICE_NR(device) (device)
20     #define DEVICE_ON(device)
21     #define DEVICE_OFF(device)
22     #define DEVICE_NO_RANDOM
23     #include <linux/blk.h>
24     /* for old kernels... */
25     #ifndef QUEUE_EMPTY
26     #define QUEUE_EMPTY  (!CURRENT)
27     #endif
28     #if LINUX_VERSION_CODE < 0x20300
29     #define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
30     #else
31     #define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
32     #endif
33     
34     #ifdef CONFIG_DEVFS_FS
35     #include <linux/devfs_fs_kernel.h>
36     static void mtd_notify_add(struct mtd_info* mtd);
37     static void mtd_notify_remove(struct mtd_info* mtd);
38     static struct mtd_notifier notifier = {
39             mtd_notify_add,
40             mtd_notify_remove,
41             NULL
42     };
43     static devfs_handle_t devfs_dir_handle = NULL;
44     static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES];
45     #endif
46     
47     static struct mtdblk_dev {
48     	struct mtd_info *mtd; /* Locked */
49     	int count;
50     	struct semaphore cache_sem;
51     	unsigned char *cache_data;
52     	unsigned long cache_offset;
53     	unsigned int cache_size;
54     	enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
55     } *mtdblks[MAX_MTD_DEVICES];
56     
57     static spinlock_t mtdblks_lock;
58     
59     static int mtd_sizes[MAX_MTD_DEVICES];
60     static int mtd_blksizes[MAX_MTD_DEVICES];
61     
62     
63     /*
64      * Cache stuff...
65      * 
66      * Since typical flash erasable sectors are much larger than what Linux's
67      * buffer cache can handle, we must implement read-modify-write on flash
68      * sectors for each block write requests.  To avoid over-erasing flash sectors
69      * and to speed things up, we locally cache a whole flash sector while it is
70      * being written to until a different sector is required.
71      */
72     
73     static void erase_callback(struct erase_info *done)
74     {
75     	wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
76     	wake_up(wait_q);
77     }
78     
79     static int erase_write (struct mtd_info *mtd, unsigned long pos, 
80     			int len, const char *buf)
81     {
82     	struct erase_info erase;
83     	DECLARE_WAITQUEUE(wait, current);
84     	wait_queue_head_t wait_q;
85     	size_t retlen;
86     	int ret;
87     
88     	/*
89     	 * First, let's erase the flash block.
90     	 */
91     
92     	init_waitqueue_head(&wait_q);
93     	erase.mtd = mtd;
94     	erase.callback = erase_callback;
95     	erase.addr = pos;
96     	erase.len = len;
97     	erase.priv = (u_long)&wait_q;
98     
99     	set_current_state(TASK_INTERRUPTIBLE);
100     	add_wait_queue(&wait_q, &wait);
101     
102     	ret = MTD_ERASE(mtd, &erase);
103     	if (ret) {
104     		set_current_state(TASK_RUNNING);
105     		remove_wait_queue(&wait_q, &wait);
106     		printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] "
107     				     "on \"%s\" failed\n",
108     			pos, len, mtd->name);
109     		return ret;
110     	}
111     
112     	schedule();  /* Wait for erase to finish. */
113     	remove_wait_queue(&wait_q, &wait);
114     
115     	/*
116     	 * Next, writhe data to flash.
117     	 */
118     
119     	ret = MTD_WRITE (mtd, pos, len, &retlen, buf);
120     	if (ret)
121     		return ret;
122     	if (retlen != len)
123     		return -EIO;
124     	return 0;
125     }
126     
127     
128     static int write_cached_data (struct mtdblk_dev *mtdblk)
129     {
130     	struct mtd_info *mtd = mtdblk->mtd;
131     	int ret;
132     
133     	if (mtdblk->cache_state != STATE_DIRTY)
134     		return 0;
135     
136     	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" "
137     			"at 0x%lx, size 0x%x\n", mtd->name, 
138     			mtdblk->cache_offset, mtdblk->cache_size);
139     	
140     	ret = erase_write (mtd, mtdblk->cache_offset, 
141     			   mtdblk->cache_size, mtdblk->cache_data);
142     	if (ret)
143     		return ret;
144     
145     	/*
146     	 * Here we could argably set the cache state to STATE_CLEAN.
147     	 * However this could lead to inconsistency since we will not 
148     	 * be notified if this content is altered on the flash by other 
149     	 * means.  Let's declare it empty and leave buffering tasks to
150     	 * the buffer cache instead.
151     	 */
152     	mtdblk->cache_state = STATE_EMPTY;
153     	return 0;
154     }
155     
156     
157     static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, 
158     			    int len, const char *buf)
159     {
160     	struct mtd_info *mtd = mtdblk->mtd;
161     	unsigned int sect_size = mtd->erasesize;
162     	size_t retlen;
163     	int ret;
164     
165     	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
166     		mtd->name, pos, len);
167     	
168     	while (len > 0) {
169     		unsigned long sect_start = (pos/sect_size)*sect_size;
170     		unsigned int offset = pos - sect_start;
171     		unsigned int size = sect_size - offset;
172     		if( size > len ) 
173     			size = len;
174     
175     		if (size == sect_size) {
176     			/* 
177     			 * We are covering a whole sector.  Thus there is no
178     			 * need to bother with the cache while it may still be
179     			 * useful for other partial writes.
180     			 */
181     			ret = erase_write (mtd, pos, size, buf);
182     			if (ret)
183     				return ret;
184     		} else {
185     			/* Partial sector: need to use the cache */
186     
187     			if (mtdblk->cache_state == STATE_DIRTY &&
188     			    mtdblk->cache_offset != sect_start) {
189     				ret = write_cached_data(mtdblk);
190     				if (ret) 
191     					return ret;
192     			}
193     
194     			if (mtdblk->cache_state == STATE_EMPTY ||
195     			    mtdblk->cache_offset != sect_start) {
196     				/* fill the cache with the current sector */
197     				mtdblk->cache_state = STATE_EMPTY;
198     				ret = MTD_READ(mtd, sect_start, sect_size, &retlen, mtdblk->cache_data);
199     				if (ret)
200     					return ret;
201     				if (retlen != sect_size)
202     					return -EIO;
203     
204     				mtdblk->cache_offset = sect_start;
205     				mtdblk->cache_size = sect_size;
206     				mtdblk->cache_state = STATE_CLEAN;
207     			}
208     
209     			/* write data to our local cache */
210     			memcpy (mtdblk->cache_data + offset, buf, size);
211     			mtdblk->cache_state = STATE_DIRTY;
212     		}
213     
214     		buf += size;
215     		pos += size;
216     		len -= size;
217     	}
218     
219     	return 0;
220     }
221     
222     
223     static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, 
224     			   int len, char *buf)
225     {
226     	struct mtd_info *mtd = mtdblk->mtd;
227     	unsigned int sect_size = mtd->erasesize;
228     	size_t retlen;
229     	int ret;
230     
231     	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", 
232     			mtd->name, pos, len);
233     	
234     	while (len > 0) {
235     		unsigned long sect_start = (pos/sect_size)*sect_size;
236     		unsigned int offset = pos - sect_start;
237     		unsigned int size = sect_size - offset;
238     		if (size > len) 
239     			size = len;
240     
241     		/*
242     		 * Check if the requested data is already cached
243     		 * Read the requested amount of data from our internal cache if it
244     		 * contains what we want, otherwise we read the data directly
245     		 * from flash.
246     		 */
247     		if (mtdblk->cache_state != STATE_EMPTY &&
248     		    mtdblk->cache_offset == sect_start) {
249     			memcpy (buf, mtdblk->cache_data + offset, size);
250     		} else {
251     			ret = MTD_READ (mtd, pos, size, &retlen, buf);
252     			if (ret)
253     				return ret;
254     			if (retlen != size)
255     				return -EIO;
256     		}
257     
258     		buf += size;
259     		pos += size;
260     		len -= size;
261     	}
262     
263     	return 0;
264     }
265     
266     
267     
268     static int mtdblock_open(struct inode *inode, struct file *file)
269     {
270     	struct mtdblk_dev *mtdblk;
271     	int dev;
272     
273     	DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
274     	
275     	if (!inode)
276     		return -EINVAL;
277     	
278     	dev = MINOR(inode->i_rdev);
279     	if (dev >= MAX_MTD_DEVICES)
280     		return -EINVAL;
281     	
282     	MOD_INC_USE_COUNT;
283     
284     	spin_lock(&mtdblks_lock);
285     
286     	/* If it's already open, no need to piss about. */
287     	if (mtdblks[dev]) {
288     		mtdblks[dev]->count++;
289     		spin_unlock(&mtdblks_lock);
290     		return 0;
291     	}
292     	
293     	/* OK, it's not open. Try to find it */
294     
295     	/* First we have to drop the lock, because we have to
296     	   to things which might sleep.
297     	*/
298     	spin_unlock(&mtdblks_lock);
299     
300     	mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
301     	if (!mtdblk) {
302     		MOD_DEC_USE_COUNT;
303     		return -ENOMEM;
304     	}
305     	memset(mtdblk, 0, sizeof(*mtdblk));
306     	mtdblk->count = 1;
307     	mtdblk->mtd = get_mtd_device(NULL, dev);
308     
309     	if (!mtdblk->mtd) {
310     		kfree(mtdblk);
311     		MOD_DEC_USE_COUNT;
312     		return -ENODEV;
313     	}
314     
315     	init_MUTEX (&mtdblk->cache_sem);
316     	mtdblk->cache_state = STATE_EMPTY;
317     	mtdblk->cache_size = mtdblk->mtd->erasesize;
318     	mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
319     	if (!mtdblk->cache_data) {
320     		put_mtd_device(mtdblk->mtd);
321     		kfree(mtdblk);
322     		MOD_DEC_USE_COUNT;
323     		return -ENOMEM;
324     	}
325     
326     	/* OK, we've created a new one. Add it to the list. */
327     
328     	spin_lock(&mtdblks_lock);
329     
330     	if (mtdblks[dev]) {
331     		/* Another CPU made one at the same time as us. */
332     		mtdblks[dev]->count++;
333     		spin_unlock(&mtdblks_lock);
334     		put_mtd_device(mtdblk->mtd);
335     		vfree(mtdblk->cache_data);
336     		kfree(mtdblk);
337     		return 0;
338     	}
339     
340     	mtdblks[dev] = mtdblk;
341     	mtd_sizes[dev] = mtdblk->mtd->size/1024;
342     	mtd_blksizes[dev] = mtdblk->mtd->erasesize;
343     	if (mtd_blksizes[dev] > PAGE_SIZE)
344     		mtd_blksizes[dev] = PAGE_SIZE;
345     	set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));
346     	
347     	spin_unlock(&mtdblks_lock);
348     	
349     	DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
350     
351     	return 0;
352     }
353     
354     static release_t mtdblock_release(struct inode *inode, struct file *file)
355     {
356     	int dev;
357     	struct mtdblk_dev *mtdblk;
358        	DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
359     
360     	if (inode == NULL)
361     		release_return(-ENODEV);
362        
363     	invalidate_device(inode->i_rdev, 1);
364     
365     	dev = MINOR(inode->i_rdev);
366     	mtdblk = mtdblks[dev];
367     
368     	down(&mtdblk->cache_sem);
369     	write_cached_data(mtdblk);
370     	up(&mtdblk->cache_sem);
371     
372     	spin_lock(&mtdblks_lock);
373     	if (!--mtdblk->count) {
374     		/* It was the last usage. Free the device */
375     		mtdblks[dev] = NULL;
376     		spin_unlock(&mtdblks_lock);
377     		if (mtdblk->mtd->sync)
378     			mtdblk->mtd->sync(mtdblk->mtd);
379     		put_mtd_device(mtdblk->mtd);
380     		vfree(mtdblk->cache_data);
381     		kfree(mtdblk);
382     	} else {
383     		spin_unlock(&mtdblks_lock);
384     	}
385     
386     	DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
387     
388     	MOD_DEC_USE_COUNT;
389     	release_return(0);
390     }  
391     
392     
393     /* 
394      * This is a special request_fn because it is executed in a process context 
395      * to be able to sleep independently of the caller.  The io_request_lock 
396      * is held upon entry and exit.
397      * The head of our request queue is considered active so there is no need 
398      * to dequeue requests before we are done.
399      */
400     static void handle_mtdblock_request(void)
401     {
402     	struct request *req;
403     	struct mtdblk_dev *mtdblk;
404     	unsigned int res;
405     
406     	for (;;) {
407     		INIT_REQUEST;
408     		req = CURRENT;
409     		spin_unlock_irq(&io_request_lock);
410     		mtdblk = mtdblks[MINOR(req->rq_dev)];
411     		res = 0;
412     
413     		if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES)
414     			panic(__FUNCTION__": minor out of bound");
415     
416     		if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
417     			goto end_req;
418     
419     		// Handle the request
420     		switch (req->cmd)
421     		{
422     			int err;
423     
424     			case READ:
425     			down(&mtdblk->cache_sem);
426     			err = do_cached_read (mtdblk, req->sector << 9, 
427     					req->current_nr_sectors << 9,
428     					req->buffer);
429     			up(&mtdblk->cache_sem);
430     			if (!err)
431     				res = 1;
432     			break;
433     
434     			case WRITE:
435     			// Read only device
436     			if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) ) 
437     				break;
438     
439     			// Do the write
440     			down(&mtdblk->cache_sem);
441     			err = do_cached_write (mtdblk, req->sector << 9,
442     					req->current_nr_sectors << 9, 
443     					req->buffer);
444     			up(&mtdblk->cache_sem);
445     			if (!err)
446     				res = 1;
447     			break;
448     		}
449     
450     end_req:
451     		spin_lock_irq(&io_request_lock);
452     		end_request(res);
453     	}
454     }
455     
456     static volatile int leaving = 0;
457     #if LINUX_VERSION_CODE > 0x020300
458     static DECLARE_MUTEX_LOCKED(thread_sem);
459     static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
460     #else
461     static struct semaphore thread_sem = MUTEX_LOCKED;
462     DECLARE_WAIT_QUEUE_HEAD(thr_wq);
463     #endif
464     
465     int mtdblock_thread(void *dummy)
466     {
467     	struct task_struct *tsk = current;
468     	DECLARE_WAITQUEUE(wait, tsk);
469     
470     	tsk->session = 1;
471     	tsk->pgrp = 1;
472     	/* we might get involved when memory gets low, so use PF_MEMALLOC */
473     	tsk->flags |= PF_MEMALLOC;
474     	strcpy(tsk->comm, "mtdblockd");
475     	tsk->tty = NULL;
476     	spin_lock_irq(&tsk->sigmask_lock);
477     	sigfillset(&tsk->blocked);
478     	recalc_sigpending(tsk);
479     	spin_unlock_irq(&tsk->sigmask_lock);
480     	exit_mm(tsk);
481     	exit_files(tsk);
482     	exit_sighand(tsk);
483     	exit_fs(tsk);
484     
485     	while (!leaving) {
486     		add_wait_queue(&thr_wq, &wait);
487     		set_current_state(TASK_INTERRUPTIBLE);
488     		spin_lock_irq(&io_request_lock);
489     		if (QUEUE_EMPTY || QUEUE_PLUGGED) {
490     			spin_unlock_irq(&io_request_lock);
491     			schedule();
492     			remove_wait_queue(&thr_wq, &wait); 
493     		} else {
494     			remove_wait_queue(&thr_wq, &wait); 
495     			set_current_state(TASK_RUNNING);
496     			handle_mtdblock_request();
497     			spin_unlock_irq(&io_request_lock);
498     		}
499     	}
500     
501     	up(&thread_sem);
502     	return 0;
503     }
504     
505     #if LINUX_VERSION_CODE < 0x20300
506     #define RQFUNC_ARG void
507     #else
508     #define RQFUNC_ARG request_queue_t *q
509     #endif
510     
511     static void mtdblock_request(RQFUNC_ARG)
512     {
513     	/* Don't do anything, except wake the thread if necessary */
514     	wake_up(&thr_wq);
515     }
516     
517     
518     static int mtdblock_ioctl(struct inode * inode, struct file * file,
519     		      unsigned int cmd, unsigned long arg)
520     {
521     	struct mtdblk_dev *mtdblk;
522     
523     	mtdblk = mtdblks[MINOR(inode->i_rdev)];
524     
525     #ifdef PARANOIA
526     	if (!mtdblk)
527     		BUG();
528     #endif
529     
530     	switch (cmd) {
531     	case BLKGETSIZE:   /* Return device size */
532     		return put_user((mtdblk->mtd->size >> 9), (long *) arg);
533     	case BLKGETSIZE64:
534     		return put_user((u64)mtdblk->mtd->size, (u64 *)arg);
535     		
536     	case BLKFLSBUF:
537     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
538     		if(!capable(CAP_SYS_ADMIN))
539     			return -EACCES;
540     #endif
541     		fsync_dev(inode->i_rdev);
542     		invalidate_buffers(inode->i_rdev);
543     		down(&mtdblk->cache_sem);
544     		write_cached_data(mtdblk);
545     		up(&mtdblk->cache_sem);
546     		if (mtdblk->mtd->sync)
547     			mtdblk->mtd->sync(mtdblk->mtd);
548     		return 0;
549     
550     	default:
551     		return -EINVAL;
552     	}
553     }
554     
555     #if LINUX_VERSION_CODE < 0x20326
556     static struct file_operations mtd_fops =
557     {
558     	open: mtdblock_open,
559     	ioctl: mtdblock_ioctl,
560     	release: mtdblock_release,
561     	read: block_read,
562     	write: block_write
563     };
564     #else
565     static struct block_device_operations mtd_fops = 
566     {
567     	open: mtdblock_open,
568     	release: mtdblock_release,
569     	ioctl: mtdblock_ioctl
570     };
571     #endif
572     
573     #ifdef CONFIG_DEVFS_FS
574     /* Notification that a new device has been added. Create the devfs entry for
575      * it. */
576     
577     static void mtd_notify_add(struct mtd_info* mtd)
578     {
579             char name[8];
580     
581             if (!mtd)
582                     return;
583     
584             sprintf(name, "%d", mtd->index);
585             devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
586                             DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index,
587                             S_IFBLK | S_IRUGO | S_IWUGO,
588                             &mtd_fops, NULL);
589     }
590     
591     static void mtd_notify_remove(struct mtd_info* mtd)
592     {
593             if (!mtd)
594                     return;
595     
596             devfs_unregister(devfs_rw_handle[mtd->index]);
597     }
598     #endif
599     
600     #if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
601     #define init_mtdblock init_module
602     #define cleanup_mtdblock cleanup_module
603     #endif
604     
605     int __init init_mtdblock(void)
606     {
607     	int i;
608     
609     	spin_lock_init(&mtdblks_lock);
610     #ifdef CONFIG_DEVFS_FS
611     	if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops))
612     	{
613     		printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
614     			MTD_BLOCK_MAJOR);
615     		return -EAGAIN;
616     	}
617     
618     	devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
619     	register_mtd_user(&notifier);
620     #else
621     	if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
622     		printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
623     		       MTD_BLOCK_MAJOR);
624     		return -EAGAIN;
625     	}
626     #endif
627     	
628     	/* We fill it in at open() time. */
629     	for (i=0; i< MAX_MTD_DEVICES; i++) {
630     		mtd_sizes[i] = 0;
631     		mtd_blksizes[i] = BLOCK_SIZE;
632     	}
633     	init_waitqueue_head(&thr_wq);
634     	/* Allow the block size to default to BLOCK_SIZE. */
635     	blksize_size[MAJOR_NR] = mtd_blksizes;
636     	blk_size[MAJOR_NR] = mtd_sizes;
637     	
638     #if LINUX_VERSION_CODE < 0x20320
639     	blk_dev[MAJOR_NR].request_fn = mtdblock_request;
640     #else
641     	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
642     #endif
643     	kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
644     	return 0;
645     }
646     
647     static void __exit cleanup_mtdblock(void)
648     {
649     	leaving = 1;
650     	wake_up(&thr_wq);
651     	down(&thread_sem);
652     #ifdef CONFIG_DEVFS_FS
653     	unregister_mtd_user(&notifier);
654     	devfs_unregister(devfs_dir_handle);
655     	devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME);
656     #else
657     	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
658     #endif
659     #if LINUX_VERSION_CODE < 0x20320
660     	blk_dev[MAJOR_NR].request_fn = NULL;
661     #else
662     	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
663     #endif
664     	blksize_size[MAJOR_NR] = NULL;
665     	blk_size[MAJOR_NR] = NULL;
666     }
667     
668     module_init(init_mtdblock);
669     module_exit(cleanup_mtdblock);
670