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