1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
2  * $Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $
3  *
4  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
5  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
6  *
7  * Based on:
8  */
9 /*======================================================================
10 
11     A Flash Translation Layer memory card driver
12 
13     This driver implements a disk-like block device driver with an
14     apparent block size of 512 bytes for flash memory cards.
15 
16     ftl_cs.c 1.62 2000/02/01 00:59:04
17 
18     The contents of this file are subject to the Mozilla Public
19     License Version 1.1 (the "License"); you may not use this file
20     except in compliance with the License. You may obtain a copy of
21     the License at http://www.mozilla.org/MPL/
22 
23     Software distributed under the License is distributed on an "AS
24     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
25     implied. See the License for the specific language governing
26     rights and limitations under the License.
27 
28     The initial developer of the original code is David A. Hinds
29     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
30     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
31 
32     Alternatively, the contents of this file may be used under the
33     terms of the GNU General Public License version 2 (the "GPL"), in
34     which case the provisions of the GPL are applicable instead of the
35     above.  If you wish to allow the use of your version of this file
36     only under the terms of the GPL and not to allow others to use
37     your version of this file under the MPL, indicate your decision
38     by deleting the provisions above and replace them with the notice
39     and other provisions required by the GPL.  If you do not delete
40     the provisions above, a recipient may use your version of this
41     file under either the MPL or the GPL.
42 
43     LEGAL NOTE: The FTL format is patented by M-Systems.  They have
44     granted a license for its use with PCMCIA devices:
45 
46      "M-Systems grants a royalty-free, non-exclusive license under
47       any presently existing M-Systems intellectual property rights
48       necessary for the design and development of FTL-compatible
49       drivers, file systems and utilities using the data formats with
50       PCMCIA PC Cards as described in the PCMCIA Flash Translation
51       Layer (FTL) Specification."
52 
53     Use of the FTL format for non-PCMCIA applications may be an
54     infringement of these patents.  For additional information,
55     contact M-Systems (http://www.m-sys.com) directly.
56 
57 ======================================================================*/
58 #include <linux/module.h>
59 #include <linux/mtd/compatmac.h>
60 #include <linux/mtd/mtd.h>
61 /*#define PSYCHO_DEBUG */
62 
63 #include <linux/kernel.h>
64 #include <linux/sched.h>
65 #include <linux/ptrace.h>
66 #include <linux/slab.h>
67 #include <linux/string.h>
68 #include <linux/timer.h>
69 #include <linux/major.h>
70 #include <linux/fs.h>
71 #include <linux/ioctl.h>
72 #include <linux/hdreg.h>
73 
74 #if (LINUX_VERSION_CODE >= 0x20100)
75 #include <linux/vmalloc.h>
76 #endif
77 #if (LINUX_VERSION_CODE >= 0x20303)
78 #include <linux/blkpg.h>
79 #endif
80 
81 #include <linux/mtd/ftl.h>
82 /*====================================================================*/
83 /* Stuff which really ought to be in compatmac.h */
84 
85 #if (LINUX_VERSION_CODE < 0x20328)
86 #define register_disk(dev, drive, minors, ops, size) \
87     do { (dev)->part[(drive)*(minors)].nr_sects = size; \
88         if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
89         resetup_one_dev(dev, drive); } while (0)
90 #endif
91 
92 #if (LINUX_VERSION_CODE < 0x20320)
93 #define BLK_DEFAULT_QUEUE(n)    blk_dev[n].request_fn
94 #define blk_init_queue(q, req)  q = (req)
95 #define blk_cleanup_queue(q)    q = NULL
96 #define request_arg_t           void
97 #else
98 #define request_arg_t           request_queue_t *q
99 #endif
100 
101 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
102 #define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
103 #define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
104 #else
105 #define BLK_INC_USE_COUNT do {} while(0)
106 #define BLK_DEC_USE_COUNT do {} while(0)
107 #endif
108 
109 /*====================================================================*/
110 
111 /* Parameters that can be set with 'insmod' */
112 static int shuffle_freq = 50;
113 MODULE_PARM(shuffle_freq, "i");
114 
115 /*====================================================================*/
116 
117 /* Major device # for FTL device */
118 #ifndef FTL_MAJOR
119 #define FTL_MAJOR	44
120 #endif
121 
122 /* Funky stuff for setting up a block device */
123 #define MAJOR_NR		FTL_MAJOR
124 #define DEVICE_NAME		"ftl"
125 #define DEVICE_REQUEST		do_ftl_request
126 #define DEVICE_ON(device)
127 #define DEVICE_OFF(device)
128 
129 #define DEVICE_NR(minor)	((minor)>>5)
130 #define REGION_NR(minor)	(((minor)>>3)&3)
131 #define PART_NR(minor)		((minor)&7)
132 #define MINOR_NR(dev,reg,part)	(((dev)<<5)+((reg)<<3)+(part))
133 
134 #include <linux/blk.h>
135 
136 /*====================================================================*/
137 
138 /* Maximum number of separate memory devices we'll allow */
139 #define MAX_DEV		4
140 
141 /* Maximum number of regions per device */
142 #define MAX_REGION	4
143 
144 /* Maximum number of partitions in an FTL region */
145 #define PART_BITS	3
146 #define MAX_PART	8
147 
148 /* Maximum number of outstanding erase requests per socket */
149 #define MAX_ERASE	8
150 
151 /* Sector size -- shouldn't need to change */
152 #define SECTOR_SIZE	512
153 
154 
155 /* Each memory region corresponds to a minor device */
156 typedef struct partition_t {
157     struct mtd_info	*mtd;
158     u_int32_t		state;
159     u_int32_t		*VirtualBlockMap;
160     u_int32_t		*VirtualPageMap;
161     u_int32_t		FreeTotal;
162     struct eun_info_t {
163 	u_int32_t		Offset;
164 	u_int32_t		EraseCount;
165 	u_int32_t		Free;
166 	u_int32_t		Deleted;
167     } *EUNInfo;
168     struct xfer_info_t {
169 	u_int32_t		Offset;
170 	u_int32_t		EraseCount;
171 	u_int16_t		state;
172     } *XferInfo;
173     u_int16_t		bam_index;
174     u_int32_t		*bam_cache;
175     u_int16_t		DataUnits;
176     u_int32_t		BlocksPerUnit;
177     erase_unit_header_t	header;
178 #if 0
179     region_info_t	region;
180     memory_handle_t	handle;
181 #endif
182     atomic_t		open;
183 } partition_t;
184 
185 partition_t *myparts[MAX_MTD_DEVICES];
186 
187 static void ftl_notify_add(struct mtd_info *mtd);
188 static void ftl_notify_remove(struct mtd_info *mtd);
189 
190 void ftl_freepart(partition_t *part);
191 
192 static struct mtd_notifier ftl_notifier = {
193 	add:	ftl_notify_add,
194 	remove:	ftl_notify_remove,
195 };
196 
197 /* Partition state flags */
198 #define FTL_FORMATTED	0x01
199 
200 /* Transfer unit states */
201 #define XFER_UNKNOWN	0x00
202 #define XFER_ERASING	0x01
203 #define XFER_ERASED	0x02
204 #define XFER_PREPARED	0x03
205 #define XFER_FAILED	0x04
206 
207 static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
208 static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
209 static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)];
210 
211 static struct gendisk ftl_gendisk = {
212     major:		FTL_MAJOR,
213     major_name:		"ftl",
214     minor_shift:	PART_BITS,
215     max_p:		MAX_PART,
216 #if (LINUX_VERSION_CODE < 0x20328)
217     max_nr:		MAX_DEV*MAX_PART,
218 #endif
219     part:		ftl_hd,
220     sizes:		ftl_sizes,
221 };
222 
223 /*====================================================================*/
224 
225 static int ftl_ioctl(struct inode *inode, struct file *file,
226 		     u_int cmd, u_long arg);
227 static int ftl_open(struct inode *inode, struct file *file);
228 static release_t ftl_close(struct inode *inode, struct file *file);
229 static int ftl_reread_partitions(int minor);
230 
231 static void ftl_erase_callback(struct erase_info *done);
232 
233 #if LINUX_VERSION_CODE < 0x20326
234 static struct file_operations ftl_blk_fops = {
235     open:	ftl_open,
236     release:	ftl_close,
237     ioctl:	ftl_ioctl,
238     read:	block_read,
239     write:	block_write,
240     fsync:	block_fsync
241 };
242 #else
243 static struct block_device_operations ftl_blk_fops = {
244 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
245     owner:	THIS_MODULE,
246 #endif
247     open:	ftl_open,
248     release:	ftl_close,
249     ioctl:	ftl_ioctl,
250 };
251 #endif
252 
253 /*======================================================================
254 
255     Scan_header() checks to see if a memory region contains an FTL
256     partition.  build_maps() reads all the erase unit headers, builds
257     the erase unit map, and then builds the virtual page map.
258 
259 ======================================================================*/
260 
scan_header(partition_t * part)261 static int scan_header(partition_t *part)
262 {
263     erase_unit_header_t header;
264     loff_t offset, max_offset;
265     int ret;
266     part->header.FormattedSize = 0;
267     max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size;
268     /* Search first megabyte for a valid FTL header */
269     for (offset = 0;
270 	 (offset + sizeof(header)) < max_offset;
271 	 offset += part->mtd->erasesize ? : 0x2000) {
272 
273 	ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret,
274 			      (unsigned char *)&header);
275 
276 	if (ret)
277 	    return ret;
278 
279 	if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
280     }
281 
282     if (offset == max_offset) {
283 	printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
284 	return -ENOENT;
285     }
286     if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 ||
287 	(header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
288 	(header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
289 	printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
290 	return -1;
291     }
292     if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
293 	printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
294 	       1 << header.EraseUnitSize,part->mtd->erasesize);
295 	return -1;
296     }
297     part->header = header;
298     return 0;
299 }
300 
build_maps(partition_t * part)301 static int build_maps(partition_t *part)
302 {
303     erase_unit_header_t header;
304     u_int16_t xvalid, xtrans, i;
305     u_int blocks, j;
306     int hdr_ok, ret = -1;
307     ssize_t retval;
308     loff_t offset;
309 
310     /* Set up erase unit maps */
311     part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
312 	part->header.NumTransferUnits;
313     part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
314 			    GFP_KERNEL);
315     if (!part->EUNInfo)
316 	    goto out;
317     for (i = 0; i < part->DataUnits; i++)
318 	part->EUNInfo[i].Offset = 0xffffffff;
319     part->XferInfo =
320 	kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
321 		GFP_KERNEL);
322     if (!part->XferInfo)
323 	    goto out_EUNInfo;
324 
325     xvalid = xtrans = 0;
326     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
327 	offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
328 		      << part->header.EraseUnitSize);
329 	ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval,
330 			      (unsigned char *)&header);
331 
332 	if (ret)
333 	    goto out_XferInfo;
334 
335 	ret = -1;
336 	/* Is this a transfer partition? */
337 	hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
338 	if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
339 	    (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
340 	    part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
341 	    part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
342 		le32_to_cpu(header.EraseCount);
343 	    xvalid++;
344 	} else {
345 	    if (xtrans == part->header.NumTransferUnits) {
346 		printk(KERN_NOTICE "ftl_cs: format error: too many "
347 		       "transfer units!\n");
348 		goto out_XferInfo;
349 	    }
350 	    if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
351 		part->XferInfo[xtrans].state = XFER_PREPARED;
352 		part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
353 	    } else {
354 		part->XferInfo[xtrans].state = XFER_UNKNOWN;
355 		/* Pick anything reasonable for the erase count */
356 		part->XferInfo[xtrans].EraseCount =
357 		    le32_to_cpu(part->header.EraseCount);
358 	    }
359 	    part->XferInfo[xtrans].Offset = offset;
360 	    xtrans++;
361 	}
362     }
363     /* Check for format trouble */
364     header = part->header;
365     if ((xtrans != header.NumTransferUnits) ||
366 	(xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
367 	printk(KERN_NOTICE "ftl_cs: format error: erase units "
368 	       "don't add up!\n");
369 	goto out_XferInfo;
370     }
371 
372     /* Set up virtual page map */
373     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
374     part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
375     if (!part->VirtualBlockMap)
376 	    goto out_XferInfo;
377 
378     memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
379     part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
380 
381     part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
382 			      GFP_KERNEL);
383     if (!part->bam_cache)
384 	    goto out_VirtualBlockMap;
385 
386     part->bam_index = 0xffff;
387     part->FreeTotal = 0;
388 
389     for (i = 0; i < part->DataUnits; i++) {
390 	part->EUNInfo[i].Free = 0;
391 	part->EUNInfo[i].Deleted = 0;
392 	offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
393 
394 	ret = part->mtd->read(part->mtd, offset,
395 			      part->BlocksPerUnit * sizeof(u_int32_t), &retval,
396 			      (unsigned char *)part->bam_cache);
397 
398 	if (ret)
399 		goto out_bam_cache;
400 
401 	for (j = 0; j < part->BlocksPerUnit; j++) {
402 	    if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
403 		part->EUNInfo[i].Free++;
404 		part->FreeTotal++;
405 	    } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
406 		     (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
407 		part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
408 		    (i << header.EraseUnitSize) + (j << header.BlockSize);
409 	    else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
410 		part->EUNInfo[i].Deleted++;
411 	}
412     }
413 
414     ret = 0;
415     goto out;
416 
417 out_bam_cache:
418     kfree(part->bam_cache);
419 out_VirtualBlockMap:
420     vfree(part->VirtualBlockMap);
421 out_XferInfo:
422     kfree(part->XferInfo);
423 out_EUNInfo:
424     kfree(part->EUNInfo);
425 out:
426     return ret;
427 } /* build_maps */
428 
429 /*======================================================================
430 
431     Erase_xfer() schedules an asynchronous erase operation for a
432     transfer unit.
433 
434 ======================================================================*/
435 
erase_xfer(partition_t * part,u_int16_t xfernum)436 static int erase_xfer(partition_t *part,
437 		      u_int16_t xfernum)
438 {
439     int ret;
440     struct xfer_info_t *xfer;
441     struct erase_info *erase;
442 
443     xfer = &part->XferInfo[xfernum];
444     DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
445     xfer->state = XFER_ERASING;
446 
447     /* Is there a free erase slot? Always in MTD. */
448 
449 
450     erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
451     if (!erase)
452             return -ENOMEM;
453 
454     erase->callback = ftl_erase_callback;
455     erase->addr = xfer->Offset;
456     erase->len = 1 << part->header.EraseUnitSize;
457     erase->priv = (u_long)part;
458 
459     ret = part->mtd->erase(part->mtd, erase);
460 
461     if (!ret)
462 	    xfer->EraseCount++;
463     else
464 	    kfree(erase);
465 
466     return ret;
467 } /* erase_xfer */
468 
469 /*======================================================================
470 
471     Prepare_xfer() takes a freshly erased transfer unit and gives
472     it an appropriate header.
473 
474 ======================================================================*/
475 
ftl_erase_callback(struct erase_info * erase)476 static void ftl_erase_callback(struct erase_info *erase)
477 {
478     partition_t *part;
479     struct xfer_info_t *xfer;
480     int i;
481 
482     /* Look up the transfer unit */
483     part = (partition_t *)(erase->priv);
484 
485     for (i = 0; i < part->header.NumTransferUnits; i++)
486 	if (part->XferInfo[i].Offset == erase->addr) break;
487 
488     if (i == part->header.NumTransferUnits) {
489 	printk(KERN_NOTICE "ftl_cs: internal error: "
490 	       "erase lookup failed!\n");
491 	return;
492     }
493 
494     xfer = &part->XferInfo[i];
495     if (erase->state == MTD_ERASE_DONE)
496 	xfer->state = XFER_ERASED;
497     else {
498 	xfer->state = XFER_FAILED;
499 	printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
500 	       erase->state);
501     }
502 
503     kfree(erase);
504 
505 } /* ftl_erase_callback */
506 
prepare_xfer(partition_t * part,int i)507 static int prepare_xfer(partition_t *part, int i)
508 {
509     erase_unit_header_t header;
510     struct xfer_info_t *xfer;
511     int nbam, ret;
512     u_int32_t ctl;
513     ssize_t retlen;
514     loff_t offset;
515 
516     xfer = &part->XferInfo[i];
517     xfer->state = XFER_FAILED;
518 
519     DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
520 
521     /* Write the transfer unit header */
522     header = part->header;
523     header.LogicalEUN = cpu_to_le16(0xffff);
524     header.EraseCount = cpu_to_le32(xfer->EraseCount);
525 
526     ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header),
527 			   &retlen, (u_char *)&header);
528 
529     if (ret) {
530 	return ret;
531     }
532 
533     /* Write the BAM stub */
534     nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
535 	    le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
536 
537     offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
538     ctl = cpu_to_le32(BLOCK_CONTROL);
539 
540     for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
541 
542 	ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
543 			       &retlen, (u_char *)&ctl);
544 
545 	if (ret)
546 	    return ret;
547     }
548     xfer->state = XFER_PREPARED;
549     return 0;
550 
551 } /* prepare_xfer */
552 
553 /*======================================================================
554 
555     Copy_erase_unit() takes a full erase block and a transfer unit,
556     copies everything to the transfer unit, then swaps the block
557     pointers.
558 
559     All data blocks are copied to the corresponding blocks in the
560     target unit, so the virtual block map does not need to be
561     updated.
562 
563 ======================================================================*/
564 
copy_erase_unit(partition_t * part,u_int16_t srcunit,u_int16_t xferunit)565 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
566 			   u_int16_t xferunit)
567 {
568     u_char buf[SECTOR_SIZE];
569     struct eun_info_t *eun;
570     struct xfer_info_t *xfer;
571     u_int32_t src, dest, free, i;
572     u_int16_t unit;
573     int ret;
574     ssize_t retlen;
575     loff_t offset;
576     u_int16_t srcunitswap = cpu_to_le16(srcunit);
577 
578     eun = &part->EUNInfo[srcunit];
579     xfer = &part->XferInfo[xferunit];
580     DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
581 	  eun->Offset, xfer->Offset);
582 
583 
584     /* Read current BAM */
585     if (part->bam_index != srcunit) {
586 
587 	offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
588 
589 	ret = part->mtd->read(part->mtd, offset,
590 			      part->BlocksPerUnit * sizeof(u_int32_t),
591 			      &retlen, (u_char *) (part->bam_cache));
592 
593 	/* mark the cache bad, in case we get an error later */
594 	part->bam_index = 0xffff;
595 
596 	if (ret) {
597 	    printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
598 	    return ret;
599 	}
600     }
601 
602     /* Write the LogicalEUN for the transfer unit */
603     xfer->state = XFER_UNKNOWN;
604     offset = xfer->Offset + 20; /* Bad! */
605     unit = cpu_to_le16(0x7fff);
606 
607     ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t),
608 			   &retlen, (u_char *) &unit);
609 
610     if (ret) {
611 	printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
612 	return ret;
613     }
614 
615     /* Copy all data blocks from source unit to transfer unit */
616     src = eun->Offset; dest = xfer->Offset;
617 
618     free = 0;
619     ret = 0;
620     for (i = 0; i < part->BlocksPerUnit; i++) {
621 	switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
622 	case BLOCK_CONTROL:
623 	    /* This gets updated later */
624 	    break;
625 	case BLOCK_DATA:
626 	case BLOCK_REPLACEMENT:
627 	    ret = part->mtd->read(part->mtd, src, SECTOR_SIZE,
628                         &retlen, (u_char *) buf);
629 	    if (ret) {
630 		printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
631 		return ret;
632             }
633 
634 
635 	    ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE,
636                         &retlen, (u_char *) buf);
637 	    if (ret)  {
638 		printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
639 		return ret;
640             }
641 
642 	    break;
643 	default:
644 	    /* All other blocks must be free */
645 	    part->bam_cache[i] = cpu_to_le32(0xffffffff);
646 	    free++;
647 	    break;
648 	}
649 	src += SECTOR_SIZE;
650 	dest += SECTOR_SIZE;
651     }
652 
653     /* Write the BAM to the transfer unit */
654     ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
655                     part->BlocksPerUnit * sizeof(int32_t), &retlen,
656 		    (u_char *)part->bam_cache);
657     if (ret) {
658 	printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
659 	return ret;
660     }
661 
662 
663     /* All clear? Then update the LogicalEUN again */
664     ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t),
665 			   &retlen, (u_char *)&srcunitswap);
666 
667     if (ret) {
668 	printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
669 	return ret;
670     }
671 
672 
673     /* Update the maps and usage stats*/
674     i = xfer->EraseCount;
675     xfer->EraseCount = eun->EraseCount;
676     eun->EraseCount = i;
677     i = xfer->Offset;
678     xfer->Offset = eun->Offset;
679     eun->Offset = i;
680     part->FreeTotal -= eun->Free;
681     part->FreeTotal += free;
682     eun->Free = free;
683     eun->Deleted = 0;
684 
685     /* Now, the cache should be valid for the new block */
686     part->bam_index = srcunit;
687 
688     return 0;
689 } /* copy_erase_unit */
690 
691 /*======================================================================
692 
693     reclaim_block() picks a full erase unit and a transfer unit and
694     then calls copy_erase_unit() to copy one to the other.  Then, it
695     schedules an erase on the expired block.
696 
697     What's a good way to decide which transfer unit and which erase
698     unit to use?  Beats me.  My way is to always pick the transfer
699     unit with the fewest erases, and usually pick the data unit with
700     the most deleted blocks.  But with a small probability, pick the
701     oldest data unit instead.  This means that we generally postpone
702     the next reclaimation as long as possible, but shuffle static
703     stuff around a bit for wear leveling.
704 
705 ======================================================================*/
706 
reclaim_block(partition_t * part)707 static int reclaim_block(partition_t *part)
708 {
709     u_int16_t i, eun, xfer;
710     u_int32_t best;
711     int queued, ret;
712 
713     DEBUG(0, "ftl_cs: reclaiming space...\n");
714     DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
715     /* Pick the least erased transfer unit */
716     best = 0xffffffff; xfer = 0xffff;
717     do {
718 	queued = 0;
719 	for (i = 0; i < part->header.NumTransferUnits; i++) {
720 	    int n=0;
721 	    if (part->XferInfo[i].state == XFER_UNKNOWN) {
722 		DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
723 		n=1;
724 		erase_xfer(part, i);
725 	    }
726 	    if (part->XferInfo[i].state == XFER_ERASING) {
727 		DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
728 		n=1;
729 		queued = 1;
730 	    }
731 	    else if (part->XferInfo[i].state == XFER_ERASED) {
732 		DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
733 		n=1;
734 		prepare_xfer(part, i);
735 	    }
736 	    if (part->XferInfo[i].state == XFER_PREPARED) {
737 		DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
738 		n=1;
739 		if (part->XferInfo[i].EraseCount <= best) {
740 		    best = part->XferInfo[i].EraseCount;
741 		    xfer = i;
742 		}
743 	    }
744 		if (!n)
745 		    DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
746 
747 	}
748 	if (xfer == 0xffff) {
749 	    if (queued) {
750 		DEBUG(1, "ftl_cs: waiting for transfer "
751 		      "unit to be prepared...\n");
752 		if (part->mtd->sync)
753 			part->mtd->sync(part->mtd);
754 	    } else {
755 		static int ne = 0;
756 		if (++ne < 5)
757 		    printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
758 			   "suitable transfer units!\n");
759 		else
760 		    DEBUG(1, "ftl_cs: reclaim failed: no "
761 			  "suitable transfer units!\n");
762 
763 		return -EIO;
764 	    }
765 	}
766     } while (xfer == 0xffff);
767 
768     eun = 0;
769     if ((jiffies % shuffle_freq) == 0) {
770 	DEBUG(1, "ftl_cs: recycling freshest block...\n");
771 	best = 0xffffffff;
772 	for (i = 0; i < part->DataUnits; i++)
773 	    if (part->EUNInfo[i].EraseCount <= best) {
774 		best = part->EUNInfo[i].EraseCount;
775 		eun = i;
776 	    }
777     } else {
778 	best = 0;
779 	for (i = 0; i < part->DataUnits; i++)
780 	    if (part->EUNInfo[i].Deleted >= best) {
781 		best = part->EUNInfo[i].Deleted;
782 		eun = i;
783 	    }
784 	if (best == 0) {
785 	    static int ne = 0;
786 	    if (++ne < 5)
787 		printk(KERN_NOTICE "ftl_cs: reclaim failed: "
788 		       "no free blocks!\n");
789 	    else
790 		DEBUG(1,"ftl_cs: reclaim failed: "
791 		       "no free blocks!\n");
792 
793 	    return -EIO;
794 	}
795     }
796     ret = copy_erase_unit(part, eun, xfer);
797     if (!ret)
798 	erase_xfer(part, xfer);
799     else
800 	printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
801     return ret;
802 } /* reclaim_block */
803 
804 /*======================================================================
805 
806     Find_free() searches for a free block.  If necessary, it updates
807     the BAM cache for the erase unit containing the free block.  It
808     returns the block index -- the erase unit is just the currently
809     cached unit.  If there are no free blocks, it returns 0 -- this
810     is never a valid data block because it contains the header.
811 
812 ======================================================================*/
813 
814 #ifdef PSYCHO_DEBUG
dump_lists(partition_t * part)815 static void dump_lists(partition_t *part)
816 {
817     int i;
818     printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
819     for (i = 0; i < part->DataUnits; i++)
820 	printk(KERN_DEBUG "ftl_cs:   unit %d: %d phys, %d free, "
821 	       "%d deleted\n", i,
822 	       part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
823 	       part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
824 }
825 #endif
826 
find_free(partition_t * part)827 static u_int32_t find_free(partition_t *part)
828 {
829     u_int16_t stop, eun;
830     u_int32_t blk;
831     size_t retlen;
832     int ret;
833 
834     /* Find an erase unit with some free space */
835     stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
836     eun = stop;
837     do {
838 	if (part->EUNInfo[eun].Free != 0) break;
839 	/* Wrap around at end of table */
840 	if (++eun == part->DataUnits) eun = 0;
841     } while (eun != stop);
842 
843     if (part->EUNInfo[eun].Free == 0)
844 	return 0;
845 
846     /* Is this unit's BAM cached? */
847     if (eun != part->bam_index) {
848 	/* Invalidate cache */
849 	part->bam_index = 0xffff;
850 
851 	ret = part->mtd->read(part->mtd,
852 		       part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
853 		       part->BlocksPerUnit * sizeof(u_int32_t),
854 		       &retlen, (u_char *) (part->bam_cache));
855 
856 	if (ret) {
857 	    printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
858 	    return 0;
859 	}
860 	part->bam_index = eun;
861     }
862 
863     /* Find a free block */
864     for (blk = 0; blk < part->BlocksPerUnit; blk++)
865 	if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
866     if (blk == part->BlocksPerUnit) {
867 #ifdef PSYCHO_DEBUG
868 	static int ne = 0;
869 	if (++ne == 1)
870 	    dump_lists(part);
871 #endif
872 	printk(KERN_NOTICE "ftl_cs: bad free list!\n");
873 	return 0;
874     }
875     DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
876     return blk;
877 
878 } /* find_free */
879 
880 /*======================================================================
881 
882     This gets a memory handle for the region corresponding to the
883     minor device number.
884 
885 ======================================================================*/
886 
ftl_open(struct inode * inode,struct file * file)887 static int ftl_open(struct inode *inode, struct file *file)
888 {
889     int minor = MINOR(inode->i_rdev);
890     partition_t *partition;
891 
892     if (minor>>4 >= MAX_MTD_DEVICES)
893 	return -ENODEV;
894 
895     partition = myparts[minor>>4];
896 
897     if (!partition)
898 	return -ENODEV;
899 
900     if (partition->state != FTL_FORMATTED)
901 	return -ENXIO;
902 
903     if (ftl_gendisk.part[minor].nr_sects == 0)
904 	return -ENXIO;
905 
906     BLK_INC_USE_COUNT;
907 
908     if (!get_mtd_device(partition->mtd, -1)) {
909 	    BLK_DEC_USE_COUNT;
910 	    return -ENXIO;
911     }
912 
913     if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
914 	    put_mtd_device(partition->mtd);
915 	    BLK_DEC_USE_COUNT;
916             return -EROFS;
917     }
918 
919     DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);
920 
921     atomic_inc(&partition->open);
922 
923     return 0;
924 }
925 
926 /*====================================================================*/
927 
ftl_close(struct inode * inode,struct file * file)928 static release_t ftl_close(struct inode *inode, struct file *file)
929 {
930     int minor = MINOR(inode->i_rdev);
931     partition_t *part = myparts[minor >> 4];
932     int i;
933 
934     DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
935 
936     /* Wait for any pending erase operations to complete */
937     if (part->mtd->sync)
938 	    part->mtd->sync(part->mtd);
939 
940     for (i = 0; i < part->header.NumTransferUnits; i++) {
941 	if (part->XferInfo[i].state == XFER_ERASED)
942 	    prepare_xfer(part, i);
943     }
944 
945     atomic_dec(&part->open);
946 
947     put_mtd_device(part->mtd);
948     BLK_DEC_USE_COUNT;
949     release_return(0);
950 } /* ftl_close */
951 
952 
953 /*======================================================================
954 
955     Read a series of sectors from an FTL partition.
956 
957 ======================================================================*/
958 
ftl_read(partition_t * part,caddr_t buffer,u_long sector,u_long nblocks)959 static int ftl_read(partition_t *part, caddr_t buffer,
960 		    u_long sector, u_long nblocks)
961 {
962     u_int32_t log_addr, bsize;
963     u_long i;
964     int ret;
965     size_t offset, retlen;
966 
967     DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
968 	  part, sector, nblocks);
969     if (!(part->state & FTL_FORMATTED)) {
970 	printk(KERN_NOTICE "ftl_cs: bad partition\n");
971 	return -EIO;
972     }
973     bsize = 1 << part->header.EraseUnitSize;
974 
975     for (i = 0; i < nblocks; i++) {
976 	if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
977 	    printk(KERN_NOTICE "ftl_cs: bad read offset\n");
978 	    return -EIO;
979 	}
980 	log_addr = part->VirtualBlockMap[sector+i];
981 	if (log_addr == 0xffffffff)
982 	    memset(buffer, 0, SECTOR_SIZE);
983 	else {
984 	    offset = (part->EUNInfo[log_addr / bsize].Offset
985 			  + (log_addr % bsize));
986 	    ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE,
987 			   &retlen, (u_char *) buffer);
988 
989 	    if (ret) {
990 		printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
991 		return ret;
992 	    }
993 	}
994 	buffer += SECTOR_SIZE;
995     }
996     return 0;
997 } /* ftl_read */
998 
999 /*======================================================================
1000 
1001     Write a series of sectors to an FTL partition
1002 
1003 ======================================================================*/
1004 
set_bam_entry(partition_t * part,u_int32_t log_addr,u_int32_t virt_addr)1005 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
1006 			 u_int32_t virt_addr)
1007 {
1008     u_int32_t bsize, blk, le_virt_addr;
1009 #ifdef PSYCHO_DEBUG
1010     u_int32_t old_addr;
1011 #endif
1012     u_int16_t eun;
1013     int ret;
1014     size_t retlen, offset;
1015 
1016     DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
1017 	  part, log_addr, virt_addr);
1018     bsize = 1 << part->header.EraseUnitSize;
1019     eun = log_addr / bsize;
1020     blk = (log_addr % bsize) / SECTOR_SIZE;
1021     offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
1022 		  le32_to_cpu(part->header.BAMOffset));
1023 
1024 #ifdef PSYCHO_DEBUG
1025     ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t),
1026                         &retlen, (u_char *)&old_addr);
1027     if (ret) {
1028 	printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
1029 	return ret;
1030     }
1031     old_addr = le32_to_cpu(old_addr);
1032 
1033     if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
1034 	((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
1035 	(!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
1036 	static int ne = 0;
1037 	if (++ne < 5) {
1038 	    printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
1039 	    printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, old = 0x%x"
1040 		   ", new = 0x%x\n", log_addr, old_addr, virt_addr);
1041 	}
1042 	return -EIO;
1043     }
1044 #endif
1045     le_virt_addr = cpu_to_le32(virt_addr);
1046     if (part->bam_index == eun) {
1047 #ifdef PSYCHO_DEBUG
1048 	if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
1049 	    static int ne = 0;
1050 	    if (++ne < 5) {
1051 		printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
1052 		       "inconsistency!\n");
1053 		printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, cache"
1054 		       " = 0x%x\n",
1055 		       le32_to_cpu(part->bam_cache[blk]), old_addr);
1056 	    }
1057 	    return -EIO;
1058 	}
1059 #endif
1060 	part->bam_cache[blk] = le_virt_addr;
1061     }
1062     ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
1063                             &retlen, (u_char *)&le_virt_addr);
1064 
1065     if (ret) {
1066 	printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
1067 	printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, new = 0x%x\n",
1068 	       log_addr, virt_addr);
1069     }
1070     return ret;
1071 } /* set_bam_entry */
1072 
ftl_write(partition_t * part,caddr_t buffer,u_long sector,u_long nblocks)1073 static int ftl_write(partition_t *part, caddr_t buffer,
1074 		     u_long sector, u_long nblocks)
1075 {
1076     u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
1077     u_long i;
1078     int ret;
1079     size_t retlen, offset;
1080 
1081     DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
1082 	  part, sector, nblocks);
1083     if (!(part->state & FTL_FORMATTED)) {
1084 	printk(KERN_NOTICE "ftl_cs: bad partition\n");
1085 	return -EIO;
1086     }
1087     /* See if we need to reclaim space, before we start */
1088     while (part->FreeTotal < nblocks) {
1089 	ret = reclaim_block(part);
1090 	if (ret)
1091 	    return ret;
1092     }
1093 
1094     bsize = 1 << part->header.EraseUnitSize;
1095 
1096     virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
1097     for (i = 0; i < nblocks; i++) {
1098 	if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
1099 	    printk(KERN_NOTICE "ftl_cs: bad write offset\n");
1100 	    return -EIO;
1101 	}
1102 
1103 	/* Grab a free block */
1104 	blk = find_free(part);
1105 	if (blk == 0) {
1106 	    static int ne = 0;
1107 	    if (++ne < 5)
1108 		printk(KERN_NOTICE "ftl_cs: internal error: "
1109 		       "no free blocks!\n");
1110 	    return -ENOSPC;
1111 	}
1112 
1113 	/* Tag the BAM entry, and write the new block */
1114 	log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
1115 	part->EUNInfo[part->bam_index].Free--;
1116 	part->FreeTotal--;
1117 	if (set_bam_entry(part, log_addr, 0xfffffffe))
1118 	    return -EIO;
1119 	part->EUNInfo[part->bam_index].Deleted++;
1120 	offset = (part->EUNInfo[part->bam_index].Offset +
1121 		      blk * SECTOR_SIZE);
1122 	ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen,
1123                                      buffer);
1124 
1125 	if (ret) {
1126 	    printk(KERN_NOTICE "ftl_cs: block write failed!\n");
1127 	    printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
1128 		   " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
1129 		   offset);
1130 	    return -EIO;
1131 	}
1132 
1133 	/* Only delete the old entry when the new entry is ready */
1134 	old_addr = part->VirtualBlockMap[sector+i];
1135 	if (old_addr != 0xffffffff) {
1136 	    part->VirtualBlockMap[sector+i] = 0xffffffff;
1137 	    part->EUNInfo[old_addr/bsize].Deleted++;
1138 	    if (set_bam_entry(part, old_addr, 0))
1139 		return -EIO;
1140 	}
1141 
1142 	/* Finally, set up the new pointers */
1143 	if (set_bam_entry(part, log_addr, virt_addr))
1144 	    return -EIO;
1145 	part->VirtualBlockMap[sector+i] = log_addr;
1146 	part->EUNInfo[part->bam_index].Deleted--;
1147 
1148 	buffer += SECTOR_SIZE;
1149 	virt_addr += SECTOR_SIZE;
1150     }
1151     return 0;
1152 } /* ftl_write */
1153 
1154 /*======================================================================
1155 
1156     IOCTL calls for getting device parameters.
1157 
1158 ======================================================================*/
1159 
ftl_ioctl(struct inode * inode,struct file * file,u_int cmd,u_long arg)1160 static int ftl_ioctl(struct inode *inode, struct file *file,
1161 		     u_int cmd, u_long arg)
1162 {
1163     struct hd_geometry *geo = (struct hd_geometry *)arg;
1164     int ret = 0, minor = MINOR(inode->i_rdev);
1165     partition_t *part= myparts[minor >> 4];
1166     u_long sect;
1167 
1168     if (!part)
1169 	return -ENODEV; /* How? */
1170 
1171     switch (cmd) {
1172     case HDIO_GETGEO:
1173 	ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
1174 	if (ret) return ret;
1175 	/* Sort of arbitrary: round size down to 4K boundary */
1176 	sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
1177 	put_user(1, (char *)&geo->heads);
1178 	put_user(8, (char *)&geo->sectors);
1179 	put_user((sect>>3), (short *)&geo->cylinders);
1180 	put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);
1181 	break;
1182     case BLKGETSIZE:
1183 	ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);
1184 	break;
1185 #ifdef BLKGETSIZE64
1186     case BLKGETSIZE64:
1187 	ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
1188 	break;
1189 #endif
1190     case BLKRRPART:
1191 	ret = ftl_reread_partitions(minor);
1192 	break;
1193 #if (LINUX_VERSION_CODE < 0x20303)
1194     case BLKFLSBUF:
1195 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
1196 	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
1197 #endif
1198 	fsync_dev(inode->i_rdev);
1199 	invalidate_buffers(inode->i_rdev);
1200 	break;
1201     RO_IOCTLS(inode->i_rdev, arg);
1202 #else
1203     case BLKROSET:
1204     case BLKROGET:
1205     case BLKFLSBUF:
1206 	ret = blk_ioctl(inode->i_rdev, cmd, arg);
1207 	break;
1208 #endif
1209     default:
1210 	ret = -EINVAL;
1211     }
1212 
1213     return ret;
1214 } /* ftl_ioctl */
1215 
1216 /*======================================================================
1217 
1218     Handler for block device requests
1219 
1220 ======================================================================*/
1221 
ftl_reread_partitions(int minor)1222 static int ftl_reread_partitions(int minor)
1223 {
1224     partition_t *part = myparts[minor >> 4];
1225     int i, whole;
1226 
1227     DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
1228     if ((atomic_read(&part->open) > 1)) {
1229 	    return -EBUSY;
1230     }
1231     whole = minor & ~(MAX_PART-1);
1232 
1233     i = MAX_PART - 1;
1234     while (i-- > 0) {
1235 	if (ftl_hd[whole+i].nr_sects > 0) {
1236 	    kdev_t rdev = MKDEV(FTL_MAJOR, whole+i);
1237 
1238 	    invalidate_device(rdev, 1);
1239 	}
1240 	ftl_hd[whole+i].start_sect = 0;
1241 	ftl_hd[whole+i].nr_sects = 0;
1242     }
1243 
1244     scan_header(part);
1245 
1246     register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
1247 		  &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
1248 
1249 #ifdef PCMCIA_DEBUG
1250     for (i = 0; i < MAX_PART; i++) {
1251 	if (ftl_hd[whole+i].nr_sects > 0)
1252 	    printk(KERN_INFO "  %d: start %ld size %ld\n", i,
1253 		   ftl_hd[whole+i].start_sect,
1254 		   ftl_hd[whole+i].nr_sects);
1255     }
1256 #endif
1257     return 0;
1258 }
1259 
1260 /*======================================================================
1261 
1262     Handler for block device requests
1263 
1264 ======================================================================*/
1265 
do_ftl_request(request_arg_t)1266 static void do_ftl_request(request_arg_t)
1267 {
1268     int ret, minor;
1269     partition_t *part;
1270 
1271     do {
1272       //	    sti();
1273 	INIT_REQUEST;
1274 
1275 	minor = MINOR(CURRENT->rq_dev);
1276 
1277 	part = myparts[minor >> 4];
1278 	if (part) {
1279 	  ret = 0;
1280 
1281 	  switch (CURRENT->cmd) {
1282 	  case READ:
1283 	    ret = ftl_read(part, CURRENT->buffer,
1284 			   CURRENT->sector+ftl_hd[minor].start_sect,
1285 			   CURRENT->current_nr_sectors);
1286 	    if (ret) printk("ftl_read returned %d\n", ret);
1287 	    break;
1288 
1289 	  case WRITE:
1290 	    ret = ftl_write(part, CURRENT->buffer,
1291 			    CURRENT->sector+ftl_hd[minor].start_sect,
1292 			    CURRENT->current_nr_sectors);
1293 	    if (ret) printk("ftl_write returned %d\n", ret);
1294 	    break;
1295 
1296 	  default:
1297 	    panic("ftl_cs: unknown block command!\n");
1298 
1299 	  }
1300 	} else {
1301 	  ret = 1;
1302 	  printk("NULL part in ftl_request\n");
1303 	}
1304 
1305 	if (!ret) {
1306 	  CURRENT->sector += CURRENT->current_nr_sectors;
1307 	}
1308 
1309 	end_request((ret == 0) ? 1 : 0);
1310     } while (1);
1311 } /* do_ftl_request */
1312 
1313 /*====================================================================*/
1314 
ftl_freepart(partition_t * part)1315 void ftl_freepart(partition_t *part)
1316 {
1317     if (part->VirtualBlockMap) {
1318 	vfree(part->VirtualBlockMap);
1319 	part->VirtualBlockMap = NULL;
1320     }
1321     if (part->VirtualPageMap) {
1322 	kfree(part->VirtualPageMap);
1323 	part->VirtualPageMap = NULL;
1324     }
1325     if (part->EUNInfo) {
1326 	kfree(part->EUNInfo);
1327 	part->EUNInfo = NULL;
1328     }
1329     if (part->XferInfo) {
1330 	kfree(part->XferInfo);
1331 	part->XferInfo = NULL;
1332     }
1333     if (part->bam_cache) {
1334 	kfree(part->bam_cache);
1335 	part->bam_cache = NULL;
1336     }
1337 
1338 } /* ftl_freepart */
1339 
ftl_notify_add(struct mtd_info * mtd)1340 static void ftl_notify_add(struct mtd_info *mtd)
1341 {
1342 	partition_t *partition;
1343 	int device;
1344 
1345 	for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
1346 		;
1347 
1348 	if (device == MAX_MTD_DEVICES) {
1349 		printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"
1350 		       "Not scanning <%s>\n", mtd->name);
1351 		return;
1352 	}
1353 
1354 	partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
1355 
1356 	if (!partition) {
1357 		printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1358 		       mtd->name);
1359 		return;
1360 	}
1361 
1362 	memset(partition, 0, sizeof(partition_t));
1363 
1364 	partition->mtd = mtd;
1365 
1366 	if ((scan_header(partition) == 0) &&
1367 	    (build_maps(partition) == 0)) {
1368 
1369 		partition->state = FTL_FORMATTED;
1370 		atomic_set(&partition->open, 0);
1371 		myparts[device] = partition;
1372 		ftl_reread_partitions(device << 4);
1373 #ifdef PCMCIA_DEBUG
1374 		printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
1375 		       le32_to_cpu(partition->header.FormattedSize) >> 10);
1376 #endif
1377 	} else
1378 		kfree(partition);
1379 }
1380 
ftl_notify_remove(struct mtd_info * mtd)1381 static void ftl_notify_remove(struct mtd_info *mtd)
1382 {
1383         int i,j;
1384 
1385 	/* Q: What happens if you try to remove a device which has
1386 	 *    a currently-open FTL partition on it?
1387 	 *
1388 	 * A: You don't. The ftl_open routine is responsible for
1389 	 *    increasing the use count of the driver module which
1390 	 *    it uses.
1391 	 */
1392 
1393 	/* That's the theory, anyway :) */
1394 
1395 	for (i=0; i< MAX_MTD_DEVICES; i++)
1396 		if (myparts[i] && myparts[i]->mtd == mtd) {
1397 
1398 			if (myparts[i]->state == FTL_FORMATTED)
1399 				ftl_freepart(myparts[i]);
1400 
1401 			myparts[i]->state = 0;
1402 			for (j=0; j<16; j++) {
1403 				ftl_gendisk.part[j].nr_sects=0;
1404 				ftl_gendisk.part[j].start_sect=0;
1405 			}
1406 			kfree(myparts[i]);
1407 			myparts[i] = NULL;
1408 		}
1409 }
1410 
init_ftl(void)1411 int init_ftl(void)
1412 {
1413     int i;
1414 
1415     memset(myparts, 0, sizeof(myparts));
1416 
1417     DEBUG(0, "$Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $\n");
1418 
1419     if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
1420 	printk(KERN_NOTICE "ftl_cs: unable to grab major "
1421 	       "device number!\n");
1422 	return -EAGAIN;
1423     }
1424 
1425     for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)
1426 	ftl_blocksizes[i] = 1024;
1427     for (i = 0; i < MAX_DEV*MAX_PART; i++) {
1428 	ftl_hd[i].nr_sects = 0;
1429 	ftl_hd[i].start_sect = 0;
1430     }
1431     blksize_size[FTL_MAJOR] = ftl_blocksizes;
1432     ftl_gendisk.major = FTL_MAJOR;
1433     blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);
1434     add_gendisk(&ftl_gendisk);
1435 
1436     register_mtd_user(&ftl_notifier);
1437 
1438     return 0;
1439 }
1440 
cleanup_ftl(void)1441 static void __exit cleanup_ftl(void)
1442 {
1443     unregister_mtd_user(&ftl_notifier);
1444 
1445     unregister_blkdev(FTL_MAJOR, "ftl");
1446     blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
1447     blksize_size[FTL_MAJOR] = NULL;
1448 
1449     del_gendisk(&ftl_gendisk);
1450 }
1451 
1452 module_init(init_ftl);
1453 module_exit(cleanup_ftl);
1454 
1455 
1456 MODULE_LICENSE("Dual MPL/GPL");
1457 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1458 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");
1459