1/*
2 * Direct MTD block device access
3 *
4 * $Id: mtdblock.c,v 1.1.1.1 2007/08/03 18:52:43 Exp $
5 *
6 * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
7 * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
8 */
9
10#include <linux/fs.h>
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/sched.h>
15#include <linux/slab.h>
16#include <linux/types.h>
17#include <linux/vmalloc.h>
18
19#include <linux/mtd/mtd.h>
20#include <linux/mtd/blktrans.h>
21#include <linux/mutex.h>
22
23
24static struct mtdblk_dev {
25	struct mtd_info *mtd;
26	int count;
27	struct mutex cache_mutex;
28	unsigned char *cache_data;
29	unsigned long cache_offset;
30	unsigned int cache_size;
31	enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
32} *mtdblks[MAX_MTD_DEVICES];
33
34/*
35 * Cache stuff...
36 *
37 * Since typical flash erasable sectors are much larger than what Linux's
38 * buffer cache can handle, we must implement read-modify-write on flash
39 * sectors for each block write requests.  To avoid over-erasing flash sectors
40 * and to speed things up, we locally cache a whole flash sector while it is
41 * being written to until a different sector is required.
42 */
43
44static void erase_callback(struct erase_info *done)
45{
46	wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
47	wake_up(wait_q);
48}
49
50static int erase_write (struct mtd_info *mtd, unsigned long pos,
51			int len, const char *buf)
52{
53	struct erase_info erase;
54	DECLARE_WAITQUEUE(wait, current);
55	wait_queue_head_t wait_q;
56	size_t retlen;
57	int ret;
58
59	/*
60	 * First, let's erase the flash block.
61	 */
62
63	init_waitqueue_head(&wait_q);
64	erase.mtd = mtd;
65	erase.callback = erase_callback;
66	erase.addr = pos;
67	erase.len = len;
68	erase.priv = (u_long)&wait_q;
69
70	set_current_state(TASK_INTERRUPTIBLE);
71	add_wait_queue(&wait_q, &wait);
72
73	ret = mtd->erase(mtd, &erase);
74	if (ret) {
75		set_current_state(TASK_RUNNING);
76		remove_wait_queue(&wait_q, &wait);
77		printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] "
78				     "on \"%s\" failed\n",
79			pos, len, mtd->name);
80		return ret;
81	}
82
83	schedule();  /* Wait for erase to finish. */
84	remove_wait_queue(&wait_q, &wait);
85
86	/*
87	 * Next, writhe data to flash.
88	 */
89
90	ret = mtd->write(mtd, pos, len, &retlen, buf);
91	if (ret)
92		return ret;
93	if (retlen != len)
94		return -EIO;
95	return 0;
96}
97
98
99static int write_cached_data (struct mtdblk_dev *mtdblk)
100{
101	struct mtd_info *mtd = mtdblk->mtd;
102	int ret;
103
104	if (mtdblk->cache_state != STATE_DIRTY)
105		return 0;
106
107	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" "
108			"at 0x%lx, size 0x%x\n", mtd->name,
109			mtdblk->cache_offset, mtdblk->cache_size);
110
111	ret = erase_write (mtd, mtdblk->cache_offset,
112			   mtdblk->cache_size, mtdblk->cache_data);
113	if (ret)
114		return ret;
115
116	/*
117	 * Here we could argubly set the cache state to STATE_CLEAN.
118	 * However this could lead to inconsistency since we will not
119	 * be notified if this content is altered on the flash by other
120	 * means.  Let's declare it empty and leave buffering tasks to
121	 * the buffer cache instead.
122	 */
123	mtdblk->cache_state = STATE_EMPTY;
124	return 0;
125}
126
127
128static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
129			    int len, const char *buf)
130{
131	struct mtd_info *mtd = mtdblk->mtd;
132	unsigned int sect_size = mtdblk->cache_size;
133	size_t retlen;
134	int ret;
135
136	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
137		mtd->name, pos, len);
138
139	if (!sect_size)
140		return mtd->write(mtd, pos, len, &retlen, buf);
141
142	while (len > 0) {
143		unsigned long sect_start = (pos/sect_size)*sect_size;
144		unsigned int offset = pos - sect_start;
145		unsigned int size = sect_size - offset;
146		if( size > len )
147			size = len;
148
149		if (size == sect_size) {
150			/*
151			 * We are covering a whole sector.  Thus there is no
152			 * need to bother with the cache while it may still be
153			 * useful for other partial writes.
154			 */
155			ret = erase_write (mtd, pos, size, buf);
156			if (ret)
157				return ret;
158		} else {
159			/* Partial sector: need to use the cache */
160
161			if (mtdblk->cache_state == STATE_DIRTY &&
162			    mtdblk->cache_offset != sect_start) {
163				ret = write_cached_data(mtdblk);
164				if (ret)
165					return ret;
166			}
167
168			if (mtdblk->cache_state == STATE_EMPTY ||
169			    mtdblk->cache_offset != sect_start) {
170				/* fill the cache with the current sector */
171				mtdblk->cache_state = STATE_EMPTY;
172				ret = mtd->read(mtd, sect_start, sect_size,
173						&retlen, mtdblk->cache_data);
174				if (ret)
175					return ret;
176				if (retlen != sect_size)
177					return -EIO;
178
179				mtdblk->cache_offset = sect_start;
180				mtdblk->cache_size = sect_size;
181				mtdblk->cache_state = STATE_CLEAN;
182			}
183
184			/* write data to our local cache */
185			memcpy (mtdblk->cache_data + offset, buf, size);
186			mtdblk->cache_state = STATE_DIRTY;
187		}
188
189		buf += size;
190		pos += size;
191		len -= size;
192	}
193
194	return 0;
195}
196
197
198static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
199			   int len, char *buf)
200{
201	struct mtd_info *mtd = mtdblk->mtd;
202	unsigned int sect_size = mtdblk->cache_size;
203	size_t retlen;
204	int ret;
205
206	DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",
207			mtd->name, pos, len);
208
209	if (!sect_size)
210		return mtd->read(mtd, pos, len, &retlen, buf);
211
212	while (len > 0) {
213		unsigned long sect_start = (pos/sect_size)*sect_size;
214		unsigned int offset = pos - sect_start;
215		unsigned int size = sect_size - offset;
216		if (size > len)
217			size = len;
218
219		/*
220		 * Check if the requested data is already cached
221		 * Read the requested amount of data from our internal cache if it
222		 * contains what we want, otherwise we read the data directly
223		 * from flash.
224		 */
225		if (mtdblk->cache_state != STATE_EMPTY &&
226		    mtdblk->cache_offset == sect_start) {
227			memcpy (buf, mtdblk->cache_data + offset, size);
228		} else {
229			ret = mtd->read(mtd, pos, size, &retlen, buf);
230			if (ret)
231				return ret;
232			if (retlen != size)
233				return -EIO;
234		}
235
236		buf += size;
237		pos += size;
238		len -= size;
239	}
240
241	return 0;
242}
243
244static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
245			      unsigned long block, char *buf)
246{
247	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
248	return do_cached_read(mtdblk, block<<9, 512, buf);
249}
250
251static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
252			      unsigned long block, char *buf)
253{
254	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
255	if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) {
256		mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
257		if (!mtdblk->cache_data)
258			return -EINTR;
259		/* -EINTR is not really correct, but it is the best match
260		 * documented in man 2 write for all cases.  We could also
261		 * return -EAGAIN sometimes, but why bother?
262		 */
263	}
264	return do_cached_write(mtdblk, block<<9, 512, buf);
265}
266
267static int mtdblock_open(struct mtd_blktrans_dev *mbd)
268{
269	struct mtdblk_dev *mtdblk;
270	struct mtd_info *mtd = mbd->mtd;
271	int dev = mbd->devnum;
272
273	DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
274
275	if (mtdblks[dev]) {
276		mtdblks[dev]->count++;
277		return 0;
278	}
279
280	/* OK, it's not open. Create cache info for it */
281	mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
282	if (!mtdblk)
283		return -ENOMEM;
284
285	mtdblk->count = 1;
286	mtdblk->mtd = mtd;
287
288	mutex_init(&mtdblk->cache_mutex);
289	mtdblk->cache_state = STATE_EMPTY;
290	if ( !(mtdblk->mtd->flags & MTD_NO_ERASE) && mtdblk->mtd->erasesize) {
291		mtdblk->cache_size = mtdblk->mtd->erasesize;
292		mtdblk->cache_data = NULL;
293	}
294
295	mtdblks[dev] = mtdblk;
296
297	DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
298
299	return 0;
300}
301
302static int mtdblock_release(struct mtd_blktrans_dev *mbd)
303{
304	int dev = mbd->devnum;
305	struct mtdblk_dev *mtdblk = mtdblks[dev];
306
307   	DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
308
309	mutex_lock(&mtdblk->cache_mutex);
310	write_cached_data(mtdblk);
311	mutex_unlock(&mtdblk->cache_mutex);
312
313	if (!--mtdblk->count) {
314		/* It was the last usage. Free the device */
315		mtdblks[dev] = NULL;
316		if (mtdblk->mtd->sync)
317			mtdblk->mtd->sync(mtdblk->mtd);
318		vfree(mtdblk->cache_data);
319		kfree(mtdblk);
320	}
321	DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
322
323	return 0;
324}
325
326static int mtdblock_flush(struct mtd_blktrans_dev *dev)
327{
328	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
329
330	mutex_lock(&mtdblk->cache_mutex);
331	write_cached_data(mtdblk);
332	mutex_unlock(&mtdblk->cache_mutex);
333
334	if (mtdblk->mtd->sync)
335		mtdblk->mtd->sync(mtdblk->mtd);
336	return 0;
337}
338
339static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
340{
341	struct mtd_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
342
343	if (!dev)
344		return;
345
346	dev->mtd = mtd;
347	dev->devnum = mtd->index;
348
349	dev->size = mtd->size >> 9;
350	dev->tr = tr;
351
352	if (!(mtd->flags & MTD_WRITEABLE))
353		dev->readonly = 1;
354
355	add_mtd_blktrans_dev(dev);
356}
357
358static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
359{
360	del_mtd_blktrans_dev(dev);
361	kfree(dev);
362}
363
364static struct mtd_blktrans_ops mtdblock_tr = {
365	.name		= "mtdblock",
366	.major		= 31,
367	.part_bits	= 0,
368	.blksize 	= 512,
369	.open		= mtdblock_open,
370	.flush		= mtdblock_flush,
371	.release	= mtdblock_release,
372	.readsect	= mtdblock_readsect,
373	.writesect	= mtdblock_writesect,
374	.add_mtd	= mtdblock_add_mtd,
375	.remove_dev	= mtdblock_remove_dev,
376	.owner		= THIS_MODULE,
377};
378
379static int __init init_mtdblock(void)
380{
381	return register_mtd_blktrans(&mtdblock_tr);
382}
383
384static void __exit cleanup_mtdblock(void)
385{
386	deregister_mtd_blktrans(&mtdblock_tr);
387}
388
389module_init(init_mtdblock);
390module_exit(cleanup_mtdblock);
391
392
393MODULE_LICENSE("GPL");
394MODULE_AUTHOR("Nicolas Pitre <nico@cam.org> et al.");
395MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to MTD devices");
396