diff options
Diffstat (limited to 'drivers/mtd/sm_ftl.c')
| -rw-r--r-- | drivers/mtd/sm_ftl.c | 103 | 
1 files changed, 58 insertions, 45 deletions
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 67822cf6c02..cf49c22673b 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -22,10 +22,10 @@ -struct workqueue_struct *cache_flush_workqueue; +static struct workqueue_struct *cache_flush_workqueue;  static int cache_timeout = 1000; -module_param(cache_timeout, bool, S_IRUGO); +module_param(cache_timeout, int, S_IRUGO);  MODULE_PARM_DESC(cache_timeout,  	"Timeout (in ms) for cache flush (1000 ms default"); @@ -34,14 +34,14 @@ module_param(debug, int, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(debug, "Debug level (0-2)"); -/* ------------------- sysfs attributtes ---------------------------------- */ +/* ------------------- sysfs attributes ---------------------------------- */  struct sm_sysfs_attribute {  	struct device_attribute dev_attr;  	char *data;  	int len;  }; -ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr, +static ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr,  		     char *buf)  {  	struct sm_sysfs_attribute *sm_attr = @@ -54,27 +54,28 @@ ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr,  #define NUM_ATTRIBUTES 1  #define SM_CIS_VENDOR_OFFSET 0x59 -struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) +static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)  {  	struct attribute_group *attr_group;  	struct attribute **attributes;  	struct sm_sysfs_attribute *vendor_attribute; +	char *vendor; -	int vendor_len = strnlen(ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, -					SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET); - -	char *vendor = kmalloc(vendor_len, GFP_KERNEL); -	memcpy(vendor, ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, vendor_len); -	vendor[vendor_len] = 0; +	vendor = kstrndup(ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, +			  SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET, GFP_KERNEL); +	if (!vendor) +		goto error1;  	/* Initialize sysfs attributes */  	vendor_attribute =  		kzalloc(sizeof(struct sm_sysfs_attribute), GFP_KERNEL); +	if (!vendor_attribute) +		goto error2;  	sysfs_attr_init(&vendor_attribute->dev_attr.attr);  	vendor_attribute->data = vendor; -	vendor_attribute->len = vendor_len; +	vendor_attribute->len = strlen(vendor);  	vendor_attribute->dev_attr.attr.name = "vendor";  	vendor_attribute->dev_attr.attr.mode = S_IRUGO;  	vendor_attribute->dev_attr.show = sm_attr_show; @@ -83,15 +84,27 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)  	/* Create array of pointers to the attributes */  	attributes = kzalloc(sizeof(struct attribute *) * (NUM_ATTRIBUTES + 1),  								GFP_KERNEL); +	if (!attributes) +		goto error3;  	attributes[0] = &vendor_attribute->dev_attr.attr;  	/* Finally create the attribute group */  	attr_group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL); +	if (!attr_group) +		goto error4;  	attr_group->attrs = attributes;  	return attr_group; +error4: +	kfree(attributes); +error3: +	kfree(vendor_attribute); +error2: +	kfree(vendor); +error1: +	return NULL;  } -void sm_delete_sysfs_attributes(struct sm_ftl *ftl) +static void sm_delete_sysfs_attributes(struct sm_ftl *ftl)  {  	struct attribute **attributes = ftl->disk_attributes->attrs;  	int i; @@ -122,7 +135,7 @@ static int sm_get_lba(uint8_t *lba)  	if ((lba[0] & 0xF8) != 0x10)  		return -2; -	/* check parity - endianess doesn't matter */ +	/* check parity - endianness doesn't matter */  	if (hweight16(*(uint16_t *)lba) & 1)  		return -2; @@ -131,7 +144,7 @@ static int sm_get_lba(uint8_t *lba)  /* - * Read LBA asscociated with block + * Read LBA associated with block   * returns -1, if block is erased   * returns -2 if error happens   */ @@ -236,11 +249,11 @@ static int sm_read_sector(struct sm_ftl *ftl,  		return 0;  	} -	/* User might not need the oob, but we do for data vertification */ +	/* User might not need the oob, but we do for data verification */  	if (!oob)  		oob = &tmp_oob; -	ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; +	ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB;  	ops.ooboffs = 0;  	ops.ooblen = SM_OOB_SIZE;  	ops.oobbuf = (void *)oob; @@ -260,12 +273,12 @@ again:  			return ret;  	} -	/* Unfortunelly, oob read will _always_ succeed, +	/* Unfortunately, oob read will _always_ succeed,  		despite card removal..... */ -	ret = mtd->read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops); +	ret = mtd_read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops);  	/* Test for unknown errors */ -	if (ret != 0 && ret != -EUCLEAN && ret != -EBADMSG) { +	if (ret != 0 && !mtd_is_bitflip_or_eccerr(ret)) {  		dbg("read of block %d at zone %d, failed due to error (%d)",  			block, zone, ret);  		goto again; @@ -290,7 +303,7 @@ again:  	}  	/* Test ECC*/ -	if (ret == -EBADMSG || +	if (mtd_is_eccerr(ret) ||  		(ftl->smallpagenand && sm_correct_sector(buffer, oob))) {  		dbg("read of block %d at zone %d, failed due to ECC error", @@ -320,17 +333,16 @@ static int sm_write_sector(struct sm_ftl *ftl,  	if (ftl->unstable)  		return -EIO; -	ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; +	ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB;  	ops.len = SM_SECTOR_SIZE;  	ops.datbuf = buffer;  	ops.ooboffs = 0;  	ops.ooblen = SM_OOB_SIZE;  	ops.oobbuf = (void *)oob; -	ret = mtd->write_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops); +	ret = mtd_write_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops);  	/* Now we assume that hardware will catch write bitflip errors */ -	/* If you are paranoid, use CONFIG_MTD_NAND_VERIFY_WRITE */  	if (ret) {  		dbg("write to block %d at zone %d, failed with error %d", @@ -431,14 +443,14 @@ static void sm_mark_block_bad(struct sm_ftl *ftl, int zone, int block)  	/* We aren't checking the return value, because we don't care */  	/* This also fails on fake xD cards, but I guess these won't expose -		any bad blocks till fail completly */ +		any bad blocks till fail completely */  	for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE)  		sm_write_sector(ftl, zone, block, boffset, NULL, &oob);  }  /*   * Erase a block within a zone - * If erase succedes, it updates free block fifo, otherwise marks block as bad + * If erase succeeds, it updates free block fifo, otherwise marks block as bad   */  static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,  			  int put_free) @@ -463,7 +475,7 @@ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,  		return -EIO;  	} -	if (mtd->erase(mtd, &erase)) { +	if (mtd_erase(mtd, &erase)) {  		sm_printk("erase of block %d in zone %d failed",  							block, zone_num);  		goto error; @@ -494,7 +506,7 @@ static void sm_erase_callback(struct erase_info *self)  	complete(&ftl->erase_completion);  } -/* Throughtly test that block is valid. */ +/* Thoroughly test that block is valid. */  static int sm_check_block(struct sm_ftl *ftl, int zone, int block)  {  	int boffset; @@ -510,7 +522,7 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block)  	for (boffset = 0; boffset < ftl->block_size;  					boffset += SM_SECTOR_SIZE) { -		/* This shoudn't happen anyway */ +		/* This shouldn't happen anyway */  		if (sm_read_sector(ftl, zone, block, boffset, NULL, &oob))  			return -2; @@ -524,7 +536,7 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block)  			return -EIO;  	} -	/* If the block is sliced (partialy erased usually) erase it */ +	/* If the block is sliced (partially erased usually) erase it */  	if (i == 2) {  		sm_erase_block(ftl, zone, block, 1);  		return 1; @@ -556,7 +568,7 @@ static const uint8_t cis_signature[] = {  };  /* Find out media parameters.   * This ideally has to be based on nand id, but for now device size is enough */ -int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd) +static int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd)  {  	int i;  	int size_in_megs = mtd->size / (1024 * 1024); @@ -629,8 +641,8 @@ int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd)  	if (!ftl->smallpagenand && mtd->oobsize < SM_OOB_SIZE)  		return -ENODEV; -	/* We use these functions for IO */ -	if (!mtd->read_oob || !mtd->write_oob) +	/* We use OOB */ +	if (!mtd_has_oob(mtd))  		return -ENODEV;  	/* Find geometry information */ @@ -862,8 +874,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)  	return 0;  } -/* Get and automaticly initialize an FTL mapping for one zone */ -struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num) +/* Get and automatically initialize an FTL mapping for one zone */ +static struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num)  {  	struct ftl_zone *zone;  	int error; @@ -884,7 +896,7 @@ struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num)  /* ----------------- cache handling ------------------------------------------*/  /* Initialize the one block cache */ -void sm_cache_init(struct sm_ftl *ftl) +static void sm_cache_init(struct sm_ftl *ftl)  {  	ftl->cache_data_invalid_bitmap = 0xFFFFFFFF;  	ftl->cache_clean = 1; @@ -894,7 +906,7 @@ void sm_cache_init(struct sm_ftl *ftl)  }  /* Put sector in one block cache */ -void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset) +static void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset)  {  	memcpy(ftl->cache_data + boffset, buffer, SM_SECTOR_SIZE);  	clear_bit(boffset / SM_SECTOR_SIZE, &ftl->cache_data_invalid_bitmap); @@ -902,7 +914,7 @@ void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset)  }  /* Read a sector from the cache */ -int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset) +static int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset)  {  	if (test_bit(boffset / SM_SECTOR_SIZE,  		&ftl->cache_data_invalid_bitmap)) @@ -913,7 +925,7 @@ int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset)  }  /* Write the cache to hardware */ -int sm_cache_flush(struct sm_ftl *ftl) +static int sm_cache_flush(struct sm_ftl *ftl)  {  	struct ftl_zone *zone; @@ -1092,7 +1104,7 @@ static int sm_flush(struct mtd_blktrans_dev *dev)  }  /* outside interface: device is released */ -static int sm_release(struct mtd_blktrans_dev *dev) +static void sm_release(struct mtd_blktrans_dev *dev)  {  	struct sm_ftl *ftl = dev->priv; @@ -1101,7 +1113,6 @@ static int sm_release(struct mtd_blktrans_dev *dev)  	cancel_work_sync(&ftl->flush_work);  	sm_cache_flush(ftl);  	mutex_unlock(&ftl->mutex); -	return 0;  }  /* outside interface: get geometry */ @@ -1178,6 +1189,8 @@ static void sm_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)  	}  	ftl->disk_attributes = sm_create_sysfs_attributes(ftl); +	if (!ftl->disk_attributes) +		goto error6;  	trans->disk_attributes = ftl->disk_attributes;  	sm_printk("Found %d MiB xD/SmartMedia FTL on mtd%d", @@ -1238,7 +1251,7 @@ static void sm_remove_dev(struct mtd_blktrans_dev *dev)  static struct mtd_blktrans_ops sm_ftl_ops = {  	.name		= "smblk", -	.major		= -1, +	.major		= 0,  	.part_bits	= SM_FTL_PARTN_BITS,  	.blksize	= SM_SECTOR_SIZE,  	.getgeo		= sm_getgeo, @@ -1258,10 +1271,10 @@ static struct mtd_blktrans_ops sm_ftl_ops = {  static __init int sm_module_init(void)  {  	int error = 0; -	cache_flush_workqueue = create_freezeable_workqueue("smflush"); -	if (IS_ERR(cache_flush_workqueue)) -		return PTR_ERR(cache_flush_workqueue); +	cache_flush_workqueue = create_freezable_workqueue("smflush"); +	if (!cache_flush_workqueue) +		return -ENOMEM;  	error = register_mtd_blktrans(&sm_ftl_ops);  	if (error)  | 
