OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [mtd/] [rfd_ftl.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * rfd_ftl.c -- resident flash disk (flash translation layer)
3
 *
4
 * Copyright (C) 2005  Sean Young <sean@mess.org>
5
 *
6
 * $Id: rfd_ftl.c,v 1.8 2006/01/15 12:51:44 sean Exp $
7
 *
8
 * This type of flash translation layer (FTL) is used by the Embedded BIOS
9
 * by General Software. It is known as the Resident Flash Disk (RFD), see:
10
 *
11
 *      http://www.gensw.com/pages/prod/bios/rfd.htm
12
 *
13
 * based on ftl.c
14
 */
15
 
16
#include <linux/hdreg.h>
17
#include <linux/init.h>
18
#include <linux/mtd/blktrans.h>
19
#include <linux/mtd/mtd.h>
20
#include <linux/vmalloc.h>
21
#include <linux/slab.h>
22
#include <linux/jiffies.h>
23
 
24
#include <asm/types.h>
25
 
26
#define const_cpu_to_le16       __constant_cpu_to_le16
27
 
28
static int block_size = 0;
29
module_param(block_size, int, 0);
30
MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size");
31
 
32
#define PREFIX "rfd_ftl: "
33
 
34
/* This major has been assigned by device@lanana.org */
35
#ifndef RFD_FTL_MAJOR
36
#define RFD_FTL_MAJOR           256
37
#endif
38
 
39
/* Maximum number of partitions in an FTL region */
40
#define PART_BITS               4
41
 
42
/* An erase unit should start with this value */
43
#define RFD_MAGIC               0x9193
44
 
45
/* the second value is 0xffff or 0xffc8; function unknown */
46
 
47
/* the third value is always 0xffff, ignored */
48
 
49
/* next is an array of mapping for each corresponding sector */
50
#define HEADER_MAP_OFFSET       3
51
#define SECTOR_DELETED          0x0000
52
#define SECTOR_ZERO             0xfffe
53
#define SECTOR_FREE             0xffff
54
 
55
#define SECTOR_SIZE             512
56
 
57
#define SECTORS_PER_TRACK       63
58
 
59
struct block {
60
        enum {
61
                BLOCK_OK,
62
                BLOCK_ERASING,
63
                BLOCK_ERASED,
64
                BLOCK_UNUSED,
65
                BLOCK_FAILED
66
        } state;
67
        int free_sectors;
68
        int used_sectors;
69
        int erases;
70
        u_long offset;
71
};
72
 
73
struct partition {
74
        struct mtd_blktrans_dev mbd;
75
 
76
        u_int block_size;               /* size of erase unit */
77
        u_int total_blocks;             /* number of erase units */
78
        u_int header_sectors_per_block; /* header sectors in erase unit */
79
        u_int data_sectors_per_block;   /* data sectors in erase unit */
80
        u_int sector_count;             /* sectors in translated disk */
81
        u_int header_size;              /* bytes in header sector */
82
        int reserved_block;             /* block next up for reclaim */
83
        int current_block;              /* block to write to */
84
        u16 *header_cache;              /* cached header */
85
 
86
        int is_reclaiming;
87
        int cylinders;
88
        int errors;
89
        u_long *sector_map;
90
        struct block *blocks;
91
};
92
 
93
static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf);
94
 
95
static int build_block_map(struct partition *part, int block_no)
96
{
97
        struct block *block = &part->blocks[block_no];
98
        int i;
99
 
100
        block->offset = part->block_size * block_no;
101
 
102
        if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) {
103
                block->state = BLOCK_UNUSED;
104
                return -ENOENT;
105
        }
106
 
107
        block->state = BLOCK_OK;
108
 
109
        for (i=0; i<part->data_sectors_per_block; i++) {
110
                u16 entry;
111
 
112
                entry = le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]);
113
 
114
                if (entry == SECTOR_DELETED)
115
                        continue;
116
 
117
                if (entry == SECTOR_FREE) {
118
                        block->free_sectors++;
119
                        continue;
120
                }
121
 
122
                if (entry == SECTOR_ZERO)
123
                        entry = 0;
124
 
125
                if (entry >= part->sector_count) {
126
                        printk(KERN_WARNING PREFIX
127
                                "'%s': unit #%d: entry %d corrupt, "
128
                                "sector %d out of range\n",
129
                                part->mbd.mtd->name, block_no, i, entry);
130
                        continue;
131
                }
132
 
133
                if (part->sector_map[entry] != -1) {
134
                        printk(KERN_WARNING PREFIX
135
                                "'%s': more than one entry for sector %d\n",
136
                                part->mbd.mtd->name, entry);
137
                        part->errors = 1;
138
                        continue;
139
                }
140
 
141
                part->sector_map[entry] = block->offset +
142
                        (i + part->header_sectors_per_block) * SECTOR_SIZE;
143
 
144
                block->used_sectors++;
145
        }
146
 
147
        if (block->free_sectors == part->data_sectors_per_block)
148
                part->reserved_block = block_no;
149
 
150
        return 0;
151
}
152
 
153
static int scan_header(struct partition *part)
154
{
155
        int sectors_per_block;
156
        int i, rc = -ENOMEM;
157
        int blocks_found;
158
        size_t retlen;
159
 
160
        sectors_per_block = part->block_size / SECTOR_SIZE;
161
        part->total_blocks = part->mbd.mtd->size / part->block_size;
162
 
163
        if (part->total_blocks < 2)
164
                return -ENOENT;
165
 
166
        /* each erase block has three bytes header, followed by the map */
167
        part->header_sectors_per_block =
168
                        ((HEADER_MAP_OFFSET + sectors_per_block) *
169
                        sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE;
170
 
171
        part->data_sectors_per_block = sectors_per_block -
172
                        part->header_sectors_per_block;
173
 
174
        part->header_size = (HEADER_MAP_OFFSET +
175
                        part->data_sectors_per_block) * sizeof(u16);
176
 
177
        part->cylinders = (part->data_sectors_per_block *
178
                        (part->total_blocks - 1) - 1) / SECTORS_PER_TRACK;
179
 
180
        part->sector_count = part->cylinders * SECTORS_PER_TRACK;
181
 
182
        part->current_block = -1;
183
        part->reserved_block = -1;
184
        part->is_reclaiming = 0;
185
 
186
        part->header_cache = kmalloc(part->header_size, GFP_KERNEL);
187
        if (!part->header_cache)
188
                goto err;
189
 
190
        part->blocks = kcalloc(part->total_blocks, sizeof(struct block),
191
                        GFP_KERNEL);
192
        if (!part->blocks)
193
                goto err;
194
 
195
        part->sector_map = vmalloc(part->sector_count * sizeof(u_long));
196
        if (!part->sector_map) {
197
                printk(KERN_ERR PREFIX "'%s': unable to allocate memory for "
198
                        "sector map", part->mbd.mtd->name);
199
                goto err;
200
        }
201
 
202
        for (i=0; i<part->sector_count; i++)
203
                part->sector_map[i] = -1;
204
 
205
        for (i=0, blocks_found=0; i<part->total_blocks; i++) {
206
                rc = part->mbd.mtd->read(part->mbd.mtd,
207
                                i * part->block_size, part->header_size,
208
                                &retlen, (u_char*)part->header_cache);
209
 
210
                if (!rc && retlen != part->header_size)
211
                        rc = -EIO;
212
 
213
                if (rc)
214
                        goto err;
215
 
216
                if (!build_block_map(part, i))
217
                        blocks_found++;
218
        }
219
 
220
        if (blocks_found == 0) {
221
                printk(KERN_NOTICE PREFIX "no RFD magic found in '%s'\n",
222
                                part->mbd.mtd->name);
223
                rc = -ENOENT;
224
                goto err;
225
        }
226
 
227
        if (part->reserved_block == -1) {
228
                printk(KERN_WARNING PREFIX "'%s': no empty erase unit found\n",
229
                                part->mbd.mtd->name);
230
 
231
                part->errors = 1;
232
        }
233
 
234
        return 0;
235
 
236
err:
237
        vfree(part->sector_map);
238
        kfree(part->header_cache);
239
        kfree(part->blocks);
240
 
241
        return rc;
242
}
243
 
244
static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *buf)
245
{
246
        struct partition *part = (struct partition*)dev;
247
        u_long addr;
248
        size_t retlen;
249
        int rc;
250
 
251
        if (sector >= part->sector_count)
252
                return -EIO;
253
 
254
        addr = part->sector_map[sector];
255
        if (addr != -1) {
256
                rc = part->mbd.mtd->read(part->mbd.mtd, addr, SECTOR_SIZE,
257
                                                &retlen, (u_char*)buf);
258
                if (!rc && retlen != SECTOR_SIZE)
259
                        rc = -EIO;
260
 
261
                if (rc) {
262
                        printk(KERN_WARNING PREFIX "error reading '%s' at "
263
                                "0x%lx\n", part->mbd.mtd->name, addr);
264
                        return rc;
265
                }
266
        } else
267
                memset(buf, 0, SECTOR_SIZE);
268
 
269
        return 0;
270
}
271
 
272
static void erase_callback(struct erase_info *erase)
273
{
274
        struct partition *part;
275
        u16 magic;
276
        int i, rc;
277
        size_t retlen;
278
 
279
        part = (struct partition*)erase->priv;
280
 
281
        i = erase->addr / part->block_size;
282
        if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) {
283
                printk(KERN_ERR PREFIX "erase callback for unknown offset %x "
284
                                "on '%s'\n", erase->addr, part->mbd.mtd->name);
285
                return;
286
        }
287
 
288
        if (erase->state != MTD_ERASE_DONE) {
289
                printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', "
290
                                "state %d\n", erase->addr,
291
                                part->mbd.mtd->name, erase->state);
292
 
293
                part->blocks[i].state = BLOCK_FAILED;
294
                part->blocks[i].free_sectors = 0;
295
                part->blocks[i].used_sectors = 0;
296
 
297
                kfree(erase);
298
 
299
                return;
300
        }
301
 
302
        magic = const_cpu_to_le16(RFD_MAGIC);
303
 
304
        part->blocks[i].state = BLOCK_ERASED;
305
        part->blocks[i].free_sectors = part->data_sectors_per_block;
306
        part->blocks[i].used_sectors = 0;
307
        part->blocks[i].erases++;
308
 
309
        rc = part->mbd.mtd->write(part->mbd.mtd,
310
                part->blocks[i].offset, sizeof(magic), &retlen,
311
                (u_char*)&magic);
312
 
313
        if (!rc && retlen != sizeof(magic))
314
                rc = -EIO;
315
 
316
        if (rc) {
317
                printk(KERN_ERR PREFIX "'%s': unable to write RFD "
318
                                "header at 0x%lx\n",
319
                                part->mbd.mtd->name,
320
                                part->blocks[i].offset);
321
                part->blocks[i].state = BLOCK_FAILED;
322
        }
323
        else
324
                part->blocks[i].state = BLOCK_OK;
325
 
326
        kfree(erase);
327
}
328
 
329
static int erase_block(struct partition *part, int block)
330
{
331
        struct erase_info *erase;
332
        int rc = -ENOMEM;
333
 
334
        erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
335
        if (!erase)
336
                goto err;
337
 
338
        erase->mtd = part->mbd.mtd;
339
        erase->callback = erase_callback;
340
        erase->addr = part->blocks[block].offset;
341
        erase->len = part->block_size;
342
        erase->priv = (u_long)part;
343
 
344
        part->blocks[block].state = BLOCK_ERASING;
345
        part->blocks[block].free_sectors = 0;
346
 
347
        rc = part->mbd.mtd->erase(part->mbd.mtd, erase);
348
 
349
        if (rc) {
350
                printk(KERN_ERR PREFIX "erase of region %x,%x on '%s' "
351
                                "failed\n", erase->addr, erase->len,
352
                                part->mbd.mtd->name);
353
                kfree(erase);
354
        }
355
 
356
err:
357
        return rc;
358
}
359
 
360
static int move_block_contents(struct partition *part, int block_no, u_long *old_sector)
361
{
362
        void *sector_data;
363
        u16 *map;
364
        size_t retlen;
365
        int i, rc = -ENOMEM;
366
 
367
        part->is_reclaiming = 1;
368
 
369
        sector_data = kmalloc(SECTOR_SIZE, GFP_KERNEL);
370
        if (!sector_data)
371
                goto err3;
372
 
373
        map = kmalloc(part->header_size, GFP_KERNEL);
374
        if (!map)
375
                goto err2;
376
 
377
        rc = part->mbd.mtd->read(part->mbd.mtd,
378
                part->blocks[block_no].offset, part->header_size,
379
                &retlen, (u_char*)map);
380
 
381
        if (!rc && retlen != part->header_size)
382
                rc = -EIO;
383
 
384
        if (rc) {
385
                printk(KERN_ERR PREFIX "error reading '%s' at "
386
                        "0x%lx\n", part->mbd.mtd->name,
387
                        part->blocks[block_no].offset);
388
 
389
                goto err;
390
        }
391
 
392
        for (i=0; i<part->data_sectors_per_block; i++) {
393
                u16 entry = le16_to_cpu(map[HEADER_MAP_OFFSET + i]);
394
                u_long addr;
395
 
396
 
397
                if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
398
                        continue;
399
 
400
                if (entry == SECTOR_ZERO)
401
                        entry = 0;
402
 
403
                /* already warned about and ignored in build_block_map() */
404
                if (entry >= part->sector_count)
405
                        continue;
406
 
407
                addr = part->blocks[block_no].offset +
408
                        (i + part->header_sectors_per_block) * SECTOR_SIZE;
409
 
410
                if (*old_sector == addr) {
411
                        *old_sector = -1;
412
                        if (!part->blocks[block_no].used_sectors--) {
413
                                rc = erase_block(part, block_no);
414
                                break;
415
                        }
416
                        continue;
417
                }
418
                rc = part->mbd.mtd->read(part->mbd.mtd, addr,
419
                        SECTOR_SIZE, &retlen, sector_data);
420
 
421
                if (!rc && retlen != SECTOR_SIZE)
422
                        rc = -EIO;
423
 
424
                if (rc) {
425
                        printk(KERN_ERR PREFIX "'%s': Unable to "
426
                                "read sector for relocation\n",
427
                                part->mbd.mtd->name);
428
 
429
                        goto err;
430
                }
431
 
432
                rc = rfd_ftl_writesect((struct mtd_blktrans_dev*)part,
433
                                entry, sector_data);
434
 
435
                if (rc)
436
                        goto err;
437
        }
438
 
439
err:
440
        kfree(map);
441
err2:
442
        kfree(sector_data);
443
err3:
444
        part->is_reclaiming = 0;
445
 
446
        return rc;
447
}
448
 
449
static int reclaim_block(struct partition *part, u_long *old_sector)
450
{
451
        int block, best_block, score, old_sector_block;
452
        int rc;
453
 
454
        /* we have a race if sync doesn't exist */
455
        if (part->mbd.mtd->sync)
456
                part->mbd.mtd->sync(part->mbd.mtd);
457
 
458
        score = 0x7fffffff; /* MAX_INT */
459
        best_block = -1;
460
        if (*old_sector != -1)
461
                old_sector_block = *old_sector / part->block_size;
462
        else
463
                old_sector_block = -1;
464
 
465
        for (block=0; block<part->total_blocks; block++) {
466
                int this_score;
467
 
468
                if (block == part->reserved_block)
469
                        continue;
470
 
471
                /*
472
                 * Postpone reclaiming if there is a free sector as
473
                 * more removed sectors is more efficient (have to move
474
                 * less).
475
                 */
476
                if (part->blocks[block].free_sectors)
477
                        return 0;
478
 
479
                this_score = part->blocks[block].used_sectors;
480
 
481
                if (block == old_sector_block)
482
                        this_score--;
483
                else {
484
                        /* no point in moving a full block */
485
                        if (part->blocks[block].used_sectors ==
486
                                        part->data_sectors_per_block)
487
                                continue;
488
                }
489
 
490
                this_score += part->blocks[block].erases;
491
 
492
                if (this_score < score) {
493
                        best_block = block;
494
                        score = this_score;
495
                }
496
        }
497
 
498
        if (best_block == -1)
499
                return -ENOSPC;
500
 
501
        part->current_block = -1;
502
        part->reserved_block = best_block;
503
 
504
        pr_debug("reclaim_block: reclaiming block #%d with %d used "
505
                 "%d free sectors\n", best_block,
506
                 part->blocks[best_block].used_sectors,
507
                 part->blocks[best_block].free_sectors);
508
 
509
        if (part->blocks[best_block].used_sectors)
510
                rc = move_block_contents(part, best_block, old_sector);
511
        else
512
                rc = erase_block(part, best_block);
513
 
514
        return rc;
515
}
516
 
517
/*
518
 * IMPROVE: It would be best to choose the block with the most deleted sectors,
519
 * because if we fill that one up first it'll have the most chance of having
520
 * the least live sectors at reclaim.
521
 */
522
static int find_free_block(struct partition *part)
523
{
524
        int block, stop;
525
 
526
        block = part->current_block == -1 ?
527
                        jiffies % part->total_blocks : part->current_block;
528
        stop = block;
529
 
530
        do {
531
                if (part->blocks[block].free_sectors &&
532
                                block != part->reserved_block)
533
                        return block;
534
 
535
                if (part->blocks[block].state == BLOCK_UNUSED)
536
                        erase_block(part, block);
537
 
538
                if (++block >= part->total_blocks)
539
                        block = 0;
540
 
541
        } while (block != stop);
542
 
543
        return -1;
544
}
545
 
546
static int find_writable_block(struct partition *part, u_long *old_sector)
547
{
548
        int rc, block;
549
        size_t retlen;
550
 
551
        block = find_free_block(part);
552
 
553
        if (block == -1) {
554
                if (!part->is_reclaiming) {
555
                        rc = reclaim_block(part, old_sector);
556
                        if (rc)
557
                                goto err;
558
 
559
                        block = find_free_block(part);
560
                }
561
 
562
                if (block == -1) {
563
                        rc = -ENOSPC;
564
                        goto err;
565
                }
566
        }
567
 
568
        rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset,
569
                part->header_size, &retlen, (u_char*)part->header_cache);
570
 
571
        if (!rc && retlen != part->header_size)
572
                rc = -EIO;
573
 
574
        if (rc) {
575
                printk(KERN_ERR PREFIX "'%s': unable to read header at "
576
                                "0x%lx\n", part->mbd.mtd->name,
577
                                part->blocks[block].offset);
578
                goto err;
579
        }
580
 
581
        part->current_block = block;
582
 
583
err:
584
        return rc;
585
}
586
 
587
static int mark_sector_deleted(struct partition *part, u_long old_addr)
588
{
589
        int block, offset, rc;
590
        u_long addr;
591
        size_t retlen;
592
        u16 del = const_cpu_to_le16(SECTOR_DELETED);
593
 
594
        block = old_addr / part->block_size;
595
        offset = (old_addr % part->block_size) / SECTOR_SIZE -
596
                part->header_sectors_per_block;
597
 
598
        addr = part->blocks[block].offset +
599
                        (HEADER_MAP_OFFSET + offset) * sizeof(u16);
600
        rc = part->mbd.mtd->write(part->mbd.mtd, addr,
601
                sizeof(del), &retlen, (u_char*)&del);
602
 
603
        if (!rc && retlen != sizeof(del))
604
                rc = -EIO;
605
 
606
        if (rc) {
607
                printk(KERN_ERR PREFIX "error writing '%s' at "
608
                        "0x%lx\n", part->mbd.mtd->name, addr);
609
                if (rc)
610
                        goto err;
611
        }
612
        if (block == part->current_block)
613
                part->header_cache[offset + HEADER_MAP_OFFSET] = del;
614
 
615
        part->blocks[block].used_sectors--;
616
 
617
        if (!part->blocks[block].used_sectors &&
618
            !part->blocks[block].free_sectors)
619
                rc = erase_block(part, block);
620
 
621
err:
622
        return rc;
623
}
624
 
625
static int find_free_sector(const struct partition *part, const struct block *block)
626
{
627
        int i, stop;
628
 
629
        i = stop = part->data_sectors_per_block - block->free_sectors;
630
 
631
        do {
632
                if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i])
633
                                == SECTOR_FREE)
634
                        return i;
635
 
636
                if (++i == part->data_sectors_per_block)
637
                        i = 0;
638
        }
639
        while(i != stop);
640
 
641
        return -1;
642
}
643
 
644
static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ulong *old_addr)
645
{
646
        struct partition *part = (struct partition*)dev;
647
        struct block *block;
648
        u_long addr;
649
        int i;
650
        int rc;
651
        size_t retlen;
652
        u16 entry;
653
 
654
        if (part->current_block == -1 ||
655
                !part->blocks[part->current_block].free_sectors) {
656
 
657
                rc = find_writable_block(part, old_addr);
658
                if (rc)
659
                        goto err;
660
        }
661
 
662
        block = &part->blocks[part->current_block];
663
 
664
        i = find_free_sector(part, block);
665
 
666
        if (i < 0) {
667
                rc = -ENOSPC;
668
                goto err;
669
        }
670
 
671
        addr = (i + part->header_sectors_per_block) * SECTOR_SIZE +
672
                block->offset;
673
        rc = part->mbd.mtd->write(part->mbd.mtd,
674
                addr, SECTOR_SIZE, &retlen, (u_char*)buf);
675
 
676
        if (!rc && retlen != SECTOR_SIZE)
677
                rc = -EIO;
678
 
679
        if (rc) {
680
                printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n",
681
                                part->mbd.mtd->name, addr);
682
                if (rc)
683
                        goto err;
684
        }
685
 
686
        part->sector_map[sector] = addr;
687
 
688
        entry = cpu_to_le16(sector == 0 ? SECTOR_ZERO : sector);
689
 
690
        part->header_cache[i + HEADER_MAP_OFFSET] = entry;
691
 
692
        addr = block->offset + (HEADER_MAP_OFFSET + i) * sizeof(u16);
693
        rc = part->mbd.mtd->write(part->mbd.mtd, addr,
694
                        sizeof(entry), &retlen, (u_char*)&entry);
695
 
696
        if (!rc && retlen != sizeof(entry))
697
                rc = -EIO;
698
 
699
        if (rc) {
700
                printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n",
701
                                part->mbd.mtd->name, addr);
702
                if (rc)
703
                        goto err;
704
        }
705
        block->used_sectors++;
706
        block->free_sectors--;
707
 
708
err:
709
        return rc;
710
}
711
 
712
static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf)
713
{
714
        struct partition *part = (struct partition*)dev;
715
        u_long old_addr;
716
        int i;
717
        int rc = 0;
718
 
719
        pr_debug("rfd_ftl_writesect(sector=0x%lx)\n", sector);
720
 
721
        if (part->reserved_block == -1) {
722
                rc = -EACCES;
723
                goto err;
724
        }
725
 
726
        if (sector >= part->sector_count) {
727
                rc = -EIO;
728
                goto err;
729
        }
730
 
731
        old_addr = part->sector_map[sector];
732
 
733
        for (i=0; i<SECTOR_SIZE; i++) {
734
                if (!buf[i])
735
                        continue;
736
 
737
                rc = do_writesect(dev, sector, buf, &old_addr);
738
                if (rc)
739
                        goto err;
740
                break;
741
        }
742
 
743
        if (i == SECTOR_SIZE)
744
                part->sector_map[sector] = -1;
745
 
746
        if (old_addr != -1)
747
                rc = mark_sector_deleted(part, old_addr);
748
 
749
err:
750
        return rc;
751
}
752
 
753
static int rfd_ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
754
{
755
        struct partition *part = (struct partition*)dev;
756
 
757
        geo->heads = 1;
758
        geo->sectors = SECTORS_PER_TRACK;
759
        geo->cylinders = part->cylinders;
760
 
761
        return 0;
762
}
763
 
764
static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
765
{
766
        struct partition *part;
767
 
768
        if (mtd->type != MTD_NORFLASH)
769
                return;
770
 
771
        part = kzalloc(sizeof(struct partition), GFP_KERNEL);
772
        if (!part)
773
                return;
774
 
775
        part->mbd.mtd = mtd;
776
 
777
        if (block_size)
778
                part->block_size = block_size;
779
        else {
780
                if (!mtd->erasesize) {
781
                        printk(KERN_WARNING PREFIX "please provide block_size");
782
                        goto out;
783
                } else
784
                        part->block_size = mtd->erasesize;
785
        }
786
 
787
        if (scan_header(part) == 0) {
788
                part->mbd.size = part->sector_count;
789
                part->mbd.tr = tr;
790
                part->mbd.devnum = -1;
791
                if (!(mtd->flags & MTD_WRITEABLE))
792
                        part->mbd.readonly = 1;
793
                else if (part->errors) {
794
                        printk(KERN_WARNING PREFIX "'%s': errors found, "
795
                                        "setting read-only\n", mtd->name);
796
                        part->mbd.readonly = 1;
797
                }
798
 
799
                printk(KERN_INFO PREFIX "name: '%s' type: %d flags %x\n",
800
                                mtd->name, mtd->type, mtd->flags);
801
 
802
                if (!add_mtd_blktrans_dev((void*)part))
803
                        return;
804
        }
805
out:
806
        kfree(part);
807
}
808
 
809
static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev)
810
{
811
        struct partition *part = (struct partition*)dev;
812
        int i;
813
 
814
        for (i=0; i<part->total_blocks; i++) {
815
                pr_debug("rfd_ftl_remove_dev:'%s': erase unit #%02d: %d erases\n",
816
                        part->mbd.mtd->name, i, part->blocks[i].erases);
817
        }
818
 
819
        del_mtd_blktrans_dev(dev);
820
        vfree(part->sector_map);
821
        kfree(part->header_cache);
822
        kfree(part->blocks);
823
        kfree(part);
824
}
825
 
826
struct mtd_blktrans_ops rfd_ftl_tr = {
827
        .name           = "rfd",
828
        .major          = RFD_FTL_MAJOR,
829
        .part_bits      = PART_BITS,
830
        .blksize        = SECTOR_SIZE,
831
 
832
        .readsect       = rfd_ftl_readsect,
833
        .writesect      = rfd_ftl_writesect,
834
        .getgeo         = rfd_ftl_getgeo,
835
        .add_mtd        = rfd_ftl_add_mtd,
836
        .remove_dev     = rfd_ftl_remove_dev,
837
        .owner          = THIS_MODULE,
838
};
839
 
840
static int __init init_rfd_ftl(void)
841
{
842
        return register_mtd_blktrans(&rfd_ftl_tr);
843
}
844
 
845
static void __exit cleanup_rfd_ftl(void)
846
{
847
        deregister_mtd_blktrans(&rfd_ftl_tr);
848
}
849
 
850
module_init(init_rfd_ftl);
851
module_exit(cleanup_rfd_ftl);
852
 
853
MODULE_LICENSE("GPL");
854
MODULE_AUTHOR("Sean Young <sean@mess.org>");
855
MODULE_DESCRIPTION("Support code for RFD Flash Translation Layer, "
856
                "used by General Software's Embedded BIOS");
857
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.