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