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