root/drivers/mtd/rfd_ftl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. build_block_map
  2. scan_header
  3. rfd_ftl_readsect
  4. erase_block
  5. move_block_contents
  6. reclaim_block
  7. find_free_block
  8. find_writable_block
  9. mark_sector_deleted
  10. find_free_sector
  11. do_writesect
  12. rfd_ftl_writesect
  13. rfd_ftl_getgeo
  14. rfd_ftl_add_mtd
  15. rfd_ftl_remove_dev
  16. init_rfd_ftl
  17. cleanup_rfd_ftl

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

/* [<][>][^][v][top][bottom][index][help] */