diff options
Diffstat (limited to 'drivers/memstick/core/mspro_block.c')
| -rw-r--r-- | drivers/memstick/core/mspro_block.c | 268 |
1 files changed, 135 insertions, 133 deletions
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index d2d2318dafa..fc145d202c4 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -17,7 +17,10 @@ #include <linux/hdreg.h> #include <linux/kthread.h> #include <linux/delay.h> +#include <linux/slab.h> +#include <linux/mutex.h> #include <linux/memstick.h> +#include <linux/module.h> #define DRIVER_NAME "mspro_block" @@ -52,14 +55,14 @@ struct mspro_sys_attr { }; struct mspro_attr_entry { - unsigned int address; - unsigned int size; + __be32 address; + __be32 size; unsigned char id; unsigned char reserved[3]; } __attribute__((packed)); struct mspro_attribute { - unsigned short signature; + __be16 signature; unsigned short version; unsigned char count; unsigned char reserved[11]; @@ -69,28 +72,28 @@ struct mspro_attribute { struct mspro_sys_info { unsigned char class; unsigned char reserved0; - unsigned short block_size; - unsigned short block_count; - unsigned short user_block_count; - unsigned short page_size; + __be16 block_size; + __be16 block_count; + __be16 user_block_count; + __be16 page_size; unsigned char reserved1[2]; unsigned char assembly_date[8]; - unsigned int serial_number; + __be32 serial_number; unsigned char assembly_maker_code; unsigned char assembly_model_code[3]; - unsigned short memory_maker_code; - unsigned short memory_model_code; + __be16 memory_maker_code; + __be16 memory_model_code; unsigned char reserved2[4]; unsigned char vcc; unsigned char vpp; - unsigned short controller_number; - unsigned short controller_function; - unsigned short start_sector; - unsigned short unit_size; + __be16 controller_number; + __be16 controller_function; + __be16 start_sector; + __be16 unit_size; unsigned char ms_sub_class; unsigned char reserved3[4]; unsigned char interface_type; - unsigned short controller_code; + __be16 controller_code; unsigned char format_type; unsigned char reserved4; unsigned char device_type; @@ -124,11 +127,11 @@ struct mspro_specfile { } __attribute__((packed)); struct mspro_devinfo { - unsigned short cylinders; - unsigned short heads; - unsigned short bytes_per_track; - unsigned short bytes_per_sector; - unsigned short sectors_per_track; + __be16 cylinders; + __be16 heads; + __be16 bytes_per_track; + __be16 bytes_per_sector; + __be16 sectors_per_track; unsigned char reserved[6]; } __attribute__((packed)); @@ -157,6 +160,13 @@ struct mspro_block_data { int (*mrq_handler)(struct memstick_dev *card, struct memstick_request **mrq); + + /* Default request setup function for data access method preferred by + * this host instance. + */ + void (*setup_transfer)(struct memstick_dev *card, + u64 offset, size_t length); + struct attribute_group attr_group; struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; @@ -172,9 +182,9 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error); /*** Block device ***/ -static int mspro_block_bd_open(struct inode *inode, struct file *filp) +static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct mspro_block_data *msb = disk->private_data; int rc = -ENXIO; @@ -182,7 +192,7 @@ static int mspro_block_bd_open(struct inode *inode, struct file *filp) if (msb && msb->card) { msb->usage_count++; - if ((filp->f_mode & FMODE_WRITE) && msb->read_only) + if ((mode & FMODE_WRITE) && msb->read_only) rc = -EROFS; else rc = 0; @@ -194,10 +204,10 @@ static int mspro_block_bd_open(struct inode *inode, struct file *filp) } -static int mspro_block_disk_release(struct gendisk *disk) +static void mspro_block_disk_release(struct gendisk *disk) { struct mspro_block_data *msb = disk->private_data; - int disk_id = disk->first_minor >> MSPRO_BLOCK_PART_SHIFT; + int disk_id = MINOR(disk_devt(disk)) >> MSPRO_BLOCK_PART_SHIFT; mutex_lock(&mspro_block_disk_lock); @@ -214,14 +224,11 @@ static int mspro_block_disk_release(struct gendisk *disk) } mutex_unlock(&mspro_block_disk_lock); - - return 0; } -static int mspro_block_bd_release(struct inode *inode, struct file *filp) +static void mspro_block_bd_release(struct gendisk *disk, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; - return mspro_block_disk_release(disk); + mspro_block_disk_release(disk); } static int mspro_block_bd_getgeo(struct block_device *bdev, @@ -236,7 +243,7 @@ static int mspro_block_bd_getgeo(struct block_device *bdev, return 0; } -static struct block_device_operations ms_block_bdops = { +static const struct block_device_operations ms_block_bdops = { .open = mspro_block_bd_open, .release = mspro_block_bd_release, .getgeo = mspro_block_bd_getgeo, @@ -339,8 +346,7 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " "GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n", date_tz, date_tz_f, - be16_to_cpu(*(unsigned short *) - &x_sys->assembly_date[1]), + be16_to_cpup((__be16 *)&x_sys->assembly_date[1]), x_sys->assembly_date[3], x_sys->assembly_date[4], x_sys->assembly_date[5], x_sys->assembly_date[6], x_sys->assembly_date[7]); @@ -656,14 +662,43 @@ has_int_reg: } } +/*** Transfer setup functions for different access methods. ***/ + +/** Setup data transfer request for SET_CMD TPC with arguments in card + * registers. + * + * @card Current media instance + * @offset Target data offset in bytes + * @length Required transfer length in bytes. + */ +static void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset, + size_t length) +{ + struct mspro_block_data *msb = memstick_get_drvdata(card); + struct mspro_param_register param = { + .system = msb->system, + .data_count = cpu_to_be16((uint16_t)(length / msb->page_size)), + /* ISO C90 warning precludes direct initialization for now. */ + .data_address = 0, + .tpc_param = 0 + }; + + do_div(offset, msb->page_size); + param.data_address = cpu_to_be32((uint32_t)offset); + + card->next_request = h_mspro_block_req_init; + msb->mrq_handler = h_mspro_block_transfer_data; + memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, + ¶m, sizeof(param)); +} + /*** Data transfer ***/ static int mspro_block_issue_req(struct memstick_dev *card, int chunk) { struct mspro_block_data *msb = memstick_get_drvdata(card); - sector_t t_sec; + u64 t_off; unsigned int count; - struct mspro_param_register param; try_again: while (chunk) { @@ -674,41 +709,27 @@ try_again: msb->req_sg); if (!msb->seg_count) { - chunk = __blk_end_request(msb->block_req, -ENOMEM, - blk_rq_cur_bytes(msb->block_req)); + chunk = __blk_end_request_cur(msb->block_req, -ENOMEM); continue; } - t_sec = msb->block_req->sector << 9; - sector_div(t_sec, msb->page_size); - - count = msb->block_req->nr_sectors << 9; - count /= msb->page_size; + t_off = blk_rq_pos(msb->block_req); + t_off <<= 9; + count = blk_rq_bytes(msb->block_req); - param.system = msb->system; - param.data_count = cpu_to_be16(count); - param.data_address = cpu_to_be32((uint32_t)t_sec); - param.tpc_param = 0; + msb->setup_transfer(card, t_off, count); msb->data_dir = rq_data_dir(msb->block_req); msb->transfer_cmd = msb->data_dir == READ ? MSPRO_CMD_READ_DATA : MSPRO_CMD_WRITE_DATA; - dev_dbg(&card->dev, "data transfer: cmd %x, " - "lba %x, count %x\n", msb->transfer_cmd, - be32_to_cpu(param.data_address), count); - - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, - ¶m, sizeof(param)); memstick_new_req(card->host); return 0; } - dev_dbg(&card->dev, "elv_next\n"); - msb->block_req = elv_next_request(msb->queue); + dev_dbg(&card->dev, "blk_fetch\n"); + msb->block_req = blk_fetch_request(msb->queue); if (!msb->block_req) { dev_dbg(&card->dev, "issue end\n"); return -EAGAIN; @@ -747,7 +768,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error) t_len *= msb->page_size; } } else - t_len = msb->block_req->nr_sectors << 9; + t_len = blk_rq_bytes(msb->block_req); dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error); @@ -807,7 +828,8 @@ static void mspro_block_start(struct memstick_dev *card) static int mspro_block_prepare_req(struct request_queue *q, struct request *req) { - if (!blk_fs_request(req) && !blk_pc_request(req)) { + if (req->cmd_type != REQ_TYPE_FS && + req->cmd_type != REQ_TYPE_BLOCK_PC) { blk_dump_rq_flags(req, "MSPro unsupported request"); return BLKPREP_KILL; } @@ -827,8 +849,8 @@ static void mspro_block_submit_req(struct request_queue *q) return; if (msb->eject) { - while ((req = elv_next_request(q)) != NULL) - end_queued_request(req, -ENODEV); + while ((req = blk_fetch_request(q)) != NULL) + __blk_end_request_all(req, -ENODEV); return; } @@ -888,14 +910,14 @@ try_again: if (rc) { printk(KERN_WARNING "%s: could not switch to 4-bit mode, error %d\n", - card->dev.bus_id, rc); + dev_name(&card->dev), rc); return 0; } msb->system = MEMSTICK_SYS_PAR4; host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4); printk(KERN_INFO "%s: switching to 4-bit parallel mode\n", - card->dev.bus_id); + dev_name(&card->dev)); if (msb->caps & MEMSTICK_CAP_PAR8) { rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR8); @@ -906,11 +928,11 @@ try_again: MEMSTICK_PAR8); printk(KERN_INFO "%s: switching to 8-bit parallel mode\n", - card->dev.bus_id); + dev_name(&card->dev)); } else printk(KERN_WARNING "%s: could not switch to 8-bit mode, error %d\n", - card->dev.bus_id, rc); + dev_name(&card->dev), rc); } card->next_request = h_mspro_block_req_init; @@ -923,7 +945,7 @@ try_again: if (rc) { printk(KERN_WARNING "%s: interface error, trying to fall back to serial\n", - card->dev.bus_id); + dev_name(&card->dev)); msb->system = MEMSTICK_SYS_SERIAL; host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); msleep(10); @@ -950,24 +972,22 @@ try_again: } /* Memory allocated for attributes by this function should be freed by - * mspro_block_data_clear, no matter if the initialization process succeded + * mspro_block_data_clear, no matter if the initialization process succeeded * or failed. */ static int mspro_block_read_attributes(struct memstick_dev *card) { struct mspro_block_data *msb = memstick_get_drvdata(card); - struct mspro_param_register param = { - .system = msb->system, - .data_count = cpu_to_be16(1), - .data_address = 0, - .tpc_param = 0 - }; struct mspro_attribute *attr = NULL; struct mspro_sys_attr *s_attr = NULL; unsigned char *buffer = NULL; int cnt, rc, attr_count; - unsigned int addr; - unsigned short page_count; + /* While normally physical device offsets, represented here by + * attr_offset and attr_len will be of large numeric types, we can be + * sure, that attributes are close enough to the beginning of the + * device, to save ourselves some trouble. + */ + unsigned int addr, attr_offset = 0, attr_len = msb->page_size; attr = kmalloc(msb->page_size, GFP_KERNEL); if (!attr) @@ -980,10 +1000,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) msb->data_dir = READ; msb->transfer_cmd = MSPRO_CMD_READ_ATRB; - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, - sizeof(param)); + msb->setup_transfer(card, attr_offset, attr_len); + memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { @@ -993,20 +1011,20 @@ static int mspro_block_read_attributes(struct memstick_dev *card) if (be16_to_cpu(attr->signature) != MSPRO_BLOCK_SIGNATURE) { printk(KERN_ERR "%s: unrecognized device signature %x\n", - card->dev.bus_id, be16_to_cpu(attr->signature)); + dev_name(&card->dev), be16_to_cpu(attr->signature)); rc = -ENODEV; goto out_free_attr; } if (attr->count > MSPRO_BLOCK_MAX_ATTRIBUTES) { printk(KERN_WARNING "%s: way too many attribute entries\n", - card->dev.bus_id); + dev_name(&card->dev)); attr_count = MSPRO_BLOCK_MAX_ATTRIBUTES; } else attr_count = attr->count; - msb->attr_group.attrs = kzalloc((attr_count + 1) - * sizeof(struct attribute), + msb->attr_group.attrs = kcalloc(attr_count + 1, + sizeof(*msb->attr_group.attrs), GFP_KERNEL); if (!msb->attr_group.attrs) { rc = -ENOMEM; @@ -1014,13 +1032,12 @@ static int mspro_block_read_attributes(struct memstick_dev *card) } msb->attr_group.name = "media_attributes"; - buffer = kmalloc(msb->page_size, GFP_KERNEL); + buffer = kmalloc(attr_len, GFP_KERNEL); if (!buffer) { rc = -ENOMEM; goto out_free_attr; } - memcpy(buffer, (char *)attr, msb->page_size); - page_count = 1; + memcpy(buffer, (char *)attr, attr_len); for (cnt = 0; cnt < attr_count; ++cnt) { s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); @@ -1031,9 +1048,10 @@ static int mspro_block_read_attributes(struct memstick_dev *card) msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; addr = be32_to_cpu(attr->entries[cnt].address); - rc = be32_to_cpu(attr->entries[cnt].size); + s_attr->size = be32_to_cpu(attr->entries[cnt].size); dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " - "size %x\n", cnt, attr->entries[cnt].id, addr, rc); + "size %zx\n", cnt, attr->entries[cnt].id, addr, + s_attr->size); s_attr->id = attr->entries[cnt].id; if (mspro_block_attr_name(s_attr->id)) snprintf(s_attr->name, sizeof(s_attr->name), "%s", @@ -1042,62 +1060,52 @@ static int mspro_block_read_attributes(struct memstick_dev *card) snprintf(s_attr->name, sizeof(s_attr->name), "attr_x%02x", attr->entries[cnt].id); + sysfs_attr_init(&s_attr->dev_attr.attr); s_attr->dev_attr.attr.name = s_attr->name; s_attr->dev_attr.attr.mode = S_IRUGO; - s_attr->dev_attr.attr.owner = THIS_MODULE; s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); - if (!rc) + if (!s_attr->size) continue; - s_attr->size = rc; - s_attr->data = kmalloc(rc, GFP_KERNEL); + s_attr->data = kmalloc(s_attr->size, GFP_KERNEL); if (!s_attr->data) { rc = -ENOMEM; goto out_free_buffer; } - if (((addr / msb->page_size) - == be32_to_cpu(param.data_address)) - && (((addr + rc - 1) / msb->page_size) - == be32_to_cpu(param.data_address))) { + if (((addr / msb->page_size) == (attr_offset / msb->page_size)) + && (((addr + s_attr->size - 1) / msb->page_size) + == (attr_offset / msb->page_size))) { memcpy(s_attr->data, buffer + addr % msb->page_size, - rc); + s_attr->size); continue; } - if (page_count <= (rc / msb->page_size)) { + attr_offset = (addr / msb->page_size) * msb->page_size; + + if ((attr_offset + attr_len) < (addr + s_attr->size)) { kfree(buffer); - page_count = (rc / msb->page_size) + 1; - buffer = kmalloc(page_count * msb->page_size, - GFP_KERNEL); + attr_len = (((addr + s_attr->size) / msb->page_size) + + 1 ) * msb->page_size - attr_offset; + buffer = kmalloc(attr_len, GFP_KERNEL); if (!buffer) { rc = -ENOMEM; goto out_free_attr; } } - param.system = msb->system; - param.data_count = cpu_to_be16((rc / msb->page_size) + 1); - param.data_address = cpu_to_be32(addr / msb->page_size); - param.tpc_param = 0; - - sg_init_one(&msb->req_sg[0], buffer, - be16_to_cpu(param.data_count) * msb->page_size); + sg_init_one(&msb->req_sg[0], buffer, attr_len); msb->seg_count = 1; msb->current_seg = 0; msb->current_page = 0; msb->data_dir = READ; msb->transfer_cmd = MSPRO_CMD_READ_ATRB; - dev_dbg(&card->dev, "reading attribute pages %x, %x\n", - be32_to_cpu(param.data_address), - be16_to_cpu(param.data_count)); + dev_dbg(&card->dev, "reading attribute range %x, %x\n", + attr_offset, attr_len); - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, - (char *)¶m, sizeof(param)); + msb->setup_transfer(card, attr_offset, attr_len); memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { @@ -1105,7 +1113,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) goto out_free_buffer; } - memcpy(s_attr->data, buffer + addr % msb->page_size, rc); + memcpy(s_attr->data, buffer + addr % msb->page_size, + s_attr->size); } rc = 0; @@ -1123,6 +1132,8 @@ static int mspro_block_init_card(struct memstick_dev *card) int rc = 0; msb->system = MEMSTICK_SYS_SERIAL; + msb->setup_transfer = h_mspro_block_setup_cmd; + card->reg_addr.r_offset = offsetof(struct mspro_register, status); card->reg_addr.r_length = sizeof(struct ms_status_register); card->reg_addr.w_offset = offsetof(struct mspro_register, param); @@ -1199,20 +1210,11 @@ static int mspro_block_init_disk(struct memstick_dev *card) msb->page_size = be16_to_cpu(sys_info->unit_size); - if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) - return -ENOMEM; - mutex_lock(&mspro_block_disk_lock); - rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id); + disk_id = idr_alloc(&mspro_block_disk_idr, card, 0, 256, GFP_KERNEL); mutex_unlock(&mspro_block_disk_lock); - - if (rc) - return rc; - - if ((disk_id << MSPRO_BLOCK_PART_SHIFT) > 255) { - rc = -ENOSPC; - goto out_release_id; - } + if (disk_id < 0) + return disk_id; msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT); if (!msb->disk) { @@ -1230,9 +1232,8 @@ static int mspro_block_init_disk(struct memstick_dev *card) blk_queue_prep_rq(msb->queue, mspro_block_prepare_req); blk_queue_bounce_limit(msb->queue, limit); - blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); - blk_queue_max_phys_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS); - blk_queue_max_hw_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS); + blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); + blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS); blk_queue_max_segment_size(msb->queue, MSPRO_BLOCK_MAX_PAGES * msb->page_size); @@ -1246,7 +1247,7 @@ static int mspro_block_init_disk(struct memstick_dev *card) sprintf(msb->disk->disk_name, "mspblk%d", disk_id); - blk_queue_hardsect_size(msb->queue, msb->page_size); + blk_queue_logical_block_size(msb->queue, msb->page_size); capacity = be16_to_cpu(sys_info->user_block_count); capacity *= be16_to_cpu(sys_info->block_size); @@ -1334,13 +1335,14 @@ static void mspro_block_remove(struct memstick_dev *card) struct mspro_block_data *msb = memstick_get_drvdata(card); unsigned long flags; - del_gendisk(msb->disk); - dev_dbg(&card->dev, "mspro block remove\n"); spin_lock_irqsave(&msb->q_lock, flags); msb->eject = 1; blk_start_queue(msb->queue); spin_unlock_irqrestore(&msb->q_lock, flags); + del_gendisk(msb->disk); + dev_dbg(&card->dev, "mspro block remove\n"); + blk_cleanup_queue(msb->queue); msb->queue = NULL; |
