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