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