aboutsummaryrefslogtreecommitdiff
path: root/drivers/memstick/core/mspro_block.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/memstick/core/mspro_block.c')
-rw-r--r--drivers/memstick/core/mspro_block.c616
1 files changed, 321 insertions, 295 deletions
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 557dbbba5cb..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"
@@ -30,6 +33,8 @@ module_param(major, int, 0644);
#define MSPRO_BLOCK_SIGNATURE 0xa5c3
#define MSPRO_BLOCK_MAX_ATTRIBUTES 41
+#define MSPRO_BLOCK_PART_SHIFT 3
+
enum {
MSPRO_BLOCK_ID_SYSINFO = 0x10,
MSPRO_BLOCK_ID_MODELNAME = 0x15,
@@ -50,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];
@@ -67,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;
@@ -122,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));
@@ -136,9 +141,8 @@ struct mspro_block_data {
unsigned int caps;
struct gendisk *disk;
struct request_queue *queue;
+ struct request *block_req;
spinlock_t q_lock;
- wait_queue_head_t q_wait;
- struct task_struct *q_thread;
unsigned short page_size;
unsigned short cylinders;
@@ -147,30 +151,40 @@ struct mspro_block_data {
unsigned char system;
unsigned char read_only:1,
- active:1,
+ eject:1,
has_request:1,
- data_dir:1;
+ data_dir:1,
+ active:1;
unsigned char transfer_cmd;
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];
unsigned int seg_count;
unsigned int current_seg;
- unsigned short current_page;
+ unsigned int current_page;
};
static DEFINE_IDR(mspro_block_disk_idr);
static DEFINE_MUTEX(mspro_block_disk_lock);
+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;
@@ -178,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;
@@ -190,15 +204,17 @@ 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 >> MEMSTICK_PART_SHIFT;
+ int disk_id = MINOR(disk_devt(disk)) >> MSPRO_BLOCK_PART_SHIFT;
mutex_lock(&mspro_block_disk_lock);
- if (msb->usage_count) {
- msb->usage_count--;
+ if (msb) {
+ if (msb->usage_count)
+ msb->usage_count--;
+
if (!msb->usage_count) {
kfree(msb);
disk->private_data = NULL;
@@ -208,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,
@@ -230,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,
@@ -333,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]);
@@ -523,11 +535,13 @@ static int h_mspro_block_req_init(struct memstick_dev *card,
static int h_mspro_block_default(struct memstick_dev *card,
struct memstick_request **mrq)
{
- complete(&card->mrq_complete);
- if (!(*mrq)->error)
- return -EAGAIN;
- else
- return (*mrq)->error;
+ return mspro_block_complete_req(card, (*mrq)->error);
+}
+
+static int h_mspro_block_default_bad(struct memstick_dev *card,
+ struct memstick_request **mrq)
+{
+ return -ENXIO;
}
static int h_mspro_block_get_ro(struct memstick_dev *card,
@@ -535,44 +549,30 @@ static int h_mspro_block_get_ro(struct memstick_dev *card,
{
struct mspro_block_data *msb = memstick_get_drvdata(card);
- if ((*mrq)->error) {
- complete(&card->mrq_complete);
- return (*mrq)->error;
+ if (!(*mrq)->error) {
+ if ((*mrq)->data[offsetof(struct ms_status_register, status0)]
+ & MEMSTICK_STATUS0_WP)
+ msb->read_only = 1;
+ else
+ msb->read_only = 0;
}
- if ((*mrq)->data[offsetof(struct ms_status_register, status0)]
- & MEMSTICK_STATUS0_WP)
- msb->read_only = 1;
- else
- msb->read_only = 0;
-
- complete(&card->mrq_complete);
- return -EAGAIN;
+ return mspro_block_complete_req(card, (*mrq)->error);
}
static int h_mspro_block_wait_for_ced(struct memstick_dev *card,
struct memstick_request **mrq)
{
- if ((*mrq)->error) {
- complete(&card->mrq_complete);
- return (*mrq)->error;
- }
-
dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]);
- if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) {
- card->current_mrq.error = -EFAULT;
- complete(&card->mrq_complete);
- return card->current_mrq.error;
+ if (!(*mrq)->error) {
+ if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR))
+ (*mrq)->error = -EFAULT;
+ else if (!((*mrq)->data[0] & MEMSTICK_INT_CED))
+ return 0;
}
- if (!((*mrq)->data[0] & MEMSTICK_INT_CED))
- return 0;
- else {
- card->current_mrq.error = 0;
- complete(&card->mrq_complete);
- return -EAGAIN;
- }
+ return mspro_block_complete_req(card, (*mrq)->error);
}
static int h_mspro_block_transfer_data(struct memstick_dev *card,
@@ -583,10 +583,8 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card,
struct scatterlist t_sg = { 0 };
size_t t_offset;
- if ((*mrq)->error) {
- complete(&card->mrq_complete);
- return (*mrq)->error;
- }
+ if ((*mrq)->error)
+ return mspro_block_complete_req(card, (*mrq)->error);
switch ((*mrq)->tpc) {
case MS_TPC_WRITE_REG:
@@ -617,8 +615,8 @@ has_int_reg:
if (msb->current_seg == msb->seg_count) {
if (t_val & MEMSTICK_INT_CED) {
- complete(&card->mrq_complete);
- return -EAGAIN;
+ return mspro_block_complete_req(card,
+ 0);
} else {
card->next_request
= h_mspro_block_wait_for_ced;
@@ -664,142 +662,202 @@ 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,
+ &param, sizeof(param));
+}
+
/*** Data transfer ***/
-static void mspro_block_process_request(struct memstick_dev *card,
- struct request *req)
+static int mspro_block_issue_req(struct memstick_dev *card, int chunk)
{
struct mspro_block_data *msb = memstick_get_drvdata(card);
- struct mspro_param_register param;
- int rc, chunk, cnt;
- unsigned short page_count;
- sector_t t_sec;
- unsigned long flags;
+ u64 t_off;
+ unsigned int count;
- do {
- page_count = 0;
+try_again:
+ while (chunk) {
+ msb->current_page = 0;
msb->current_seg = 0;
- msb->seg_count = blk_rq_map_sg(req->q, req, msb->req_sg);
+ msb->seg_count = blk_rq_map_sg(msb->block_req->q,
+ msb->block_req,
+ msb->req_sg);
- if (msb->seg_count) {
- msb->current_page = 0;
- for (rc = 0; rc < msb->seg_count; rc++)
- page_count += msb->req_sg[rc].length
- / msb->page_size;
-
- t_sec = req->sector;
- sector_div(t_sec, msb->page_size >> 9);
- param.system = msb->system;
- param.data_count = cpu_to_be16(page_count);
- param.data_address = cpu_to_be32((uint32_t)t_sec);
- param.tpc_param = 0;
-
- msb->data_dir = rq_data_dir(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),
- page_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,
- &param, sizeof(param));
- memstick_new_req(card->host);
- wait_for_completion(&card->mrq_complete);
- rc = card->current_mrq.error;
+ if (!msb->seg_count) {
+ chunk = __blk_end_request_cur(msb->block_req, -ENOMEM);
+ continue;
+ }
- if (rc || (card->current_mrq.tpc == MSPRO_CMD_STOP)) {
- for (cnt = 0; cnt < msb->current_seg; cnt++)
- page_count += msb->req_sg[cnt].length
- / msb->page_size;
-
- if (msb->current_page)
- page_count += msb->current_page - 1;
-
- if (page_count && (msb->data_dir == READ))
- rc = msb->page_size * page_count;
- else
- rc = -EIO;
- } else
- rc = msb->page_size * page_count;
- } else
- rc = -EFAULT;
+ t_off = blk_rq_pos(msb->block_req);
+ t_off <<= 9;
+ count = blk_rq_bytes(msb->block_req);
- spin_lock_irqsave(&msb->q_lock, flags);
- if (rc >= 0)
- chunk = __blk_end_request(req, 0, rc);
- else
- chunk = __blk_end_request(req, rc, 0);
+ msb->setup_transfer(card, t_off, count);
- dev_dbg(&card->dev, "end chunk %d, %d\n", rc, chunk);
- spin_unlock_irqrestore(&msb->q_lock, flags);
- } while (chunk);
+ msb->data_dir = rq_data_dir(msb->block_req);
+ msb->transfer_cmd = msb->data_dir == READ
+ ? MSPRO_CMD_READ_DATA
+ : MSPRO_CMD_WRITE_DATA;
+
+ memstick_new_req(card->host);
+ return 0;
+ }
+
+ 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;
+ }
+
+ dev_dbg(&card->dev, "trying again\n");
+ chunk = 1;
+ goto try_again;
}
-static int mspro_block_has_request(struct mspro_block_data *msb)
+static int mspro_block_complete_req(struct memstick_dev *card, int error)
{
- int rc = 0;
+ struct mspro_block_data *msb = memstick_get_drvdata(card);
+ int chunk, cnt;
+ unsigned int t_len = 0;
unsigned long flags;
spin_lock_irqsave(&msb->q_lock, flags);
- if (kthread_should_stop() || msb->has_request)
- rc = 1;
+ dev_dbg(&card->dev, "complete %d, %d\n", msb->has_request ? 1 : 0,
+ error);
+
+ if (msb->has_request) {
+ /* Nothing to do - not really an error */
+ if (error == -EAGAIN)
+ error = 0;
+
+ if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) {
+ if (msb->data_dir == READ) {
+ for (cnt = 0; cnt < msb->current_seg; cnt++)
+ t_len += msb->req_sg[cnt].length
+ / msb->page_size;
+
+ if (msb->current_page)
+ t_len += msb->current_page - 1;
+
+ t_len *= msb->page_size;
+ }
+ } else
+ t_len = blk_rq_bytes(msb->block_req);
+
+ dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error);
+
+ if (error && !t_len)
+ t_len = blk_rq_cur_bytes(msb->block_req);
+
+ chunk = __blk_end_request(msb->block_req, error, t_len);
+
+ error = mspro_block_issue_req(card, chunk);
+
+ if (!error)
+ goto out;
+ else
+ msb->has_request = 0;
+ } else {
+ if (!error)
+ error = -EAGAIN;
+ }
+
+ card->next_request = h_mspro_block_default_bad;
+ complete_all(&card->mrq_complete);
+out:
spin_unlock_irqrestore(&msb->q_lock, flags);
- return rc;
+ return error;
}
-static int mspro_block_queue_thread(void *data)
+static void mspro_block_stop(struct memstick_dev *card)
{
- struct memstick_dev *card = data;
- struct memstick_host *host = card->host;
struct mspro_block_data *msb = memstick_get_drvdata(card);
- struct request *req;
+ int rc = 0;
unsigned long flags;
while (1) {
- wait_event(msb->q_wait, mspro_block_has_request(msb));
- dev_dbg(&card->dev, "thread iter\n");
-
spin_lock_irqsave(&msb->q_lock, flags);
- req = elv_next_request(msb->queue);
- dev_dbg(&card->dev, "next req %p\n", req);
- if (!req) {
- msb->has_request = 0;
- if (kthread_should_stop()) {
- spin_unlock_irqrestore(&msb->q_lock, flags);
- break;
- }
- } else
- msb->has_request = 1;
+ if (!msb->has_request) {
+ blk_stop_queue(msb->queue);
+ rc = 1;
+ }
spin_unlock_irqrestore(&msb->q_lock, flags);
- if (req) {
- mutex_lock(&host->lock);
- mspro_block_process_request(card, req);
- mutex_unlock(&host->lock);
- }
+ if (rc)
+ break;
+
+ wait_for_completion(&card->mrq_complete);
}
- dev_dbg(&card->dev, "thread finished\n");
- return 0;
}
-static void mspro_block_request(struct request_queue *q)
+static void mspro_block_start(struct memstick_dev *card)
+{
+ struct mspro_block_data *msb = memstick_get_drvdata(card);
+ unsigned long flags;
+
+ spin_lock_irqsave(&msb->q_lock, flags);
+ blk_start_queue(msb->queue);
+ spin_unlock_irqrestore(&msb->q_lock, flags);
+}
+
+static int mspro_block_prepare_req(struct request_queue *q, struct 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;
+ }
+
+ req->cmd_flags |= REQ_DONTPREP;
+
+ return BLKPREP_OK;
+}
+
+static void mspro_block_submit_req(struct request_queue *q)
{
struct memstick_dev *card = q->queuedata;
struct mspro_block_data *msb = memstick_get_drvdata(card);
struct request *req = NULL;
- if (msb->q_thread) {
- msb->has_request = 1;
- wake_up_all(&msb->q_wait);
- } else {
- while ((req = elv_next_request(q)) != NULL)
- end_queued_request(req, -ENODEV);
+ if (msb->has_request)
+ return;
+
+ if (msb->eject) {
+ while ((req = blk_fetch_request(q)) != NULL)
+ __blk_end_request_all(req, -ENODEV);
+
+ return;
}
+
+ msb->has_request = 1;
+ if (mspro_block_issue_req(card, 0))
+ msb->has_request = 0;
}
/*** Initialization ***/
@@ -843,6 +901,7 @@ static int mspro_block_switch_interface(struct memstick_dev *card)
struct mspro_block_data *msb = memstick_get_drvdata(card);
int rc = 0;
+try_again:
if (msb->caps & MEMSTICK_CAP_PAR4)
rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR4);
else
@@ -851,14 +910,14 @@ static int mspro_block_switch_interface(struct memstick_dev *card)
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);
@@ -869,11 +928,11 @@ static int mspro_block_switch_interface(struct memstick_dev *card)
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;
@@ -886,7 +945,7 @@ static int mspro_block_switch_interface(struct memstick_dev *card)
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);
@@ -896,29 +955,39 @@ static int mspro_block_switch_interface(struct memstick_dev *card)
rc = memstick_set_rw_addr(card);
if (!rc)
rc = mspro_block_set_interface(card, msb->system);
+
+ if (!rc) {
+ msleep(150);
+ rc = mspro_block_wait_for_ced(card);
+ if (rc)
+ return rc;
+
+ if (msb->caps & MEMSTICK_CAP_PAR8) {
+ msb->caps &= ~MEMSTICK_CAP_PAR8;
+ goto try_again;
+ }
+ }
}
return rc;
}
/* 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)
@@ -931,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, &param,
- 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) {
@@ -944,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;
@@ -965,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);
@@ -982,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",
@@ -993,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 *)&param, 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) {
@@ -1056,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;
@@ -1074,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);
@@ -1083,14 +1143,16 @@ static int mspro_block_init_card(struct memstick_dev *card)
return -EIO;
msb->caps = host->caps;
- rc = mspro_block_switch_interface(card);
+
+ msleep(150);
+ rc = mspro_block_wait_for_ced(card);
if (rc)
return rc;
- msleep(200);
- rc = mspro_block_wait_for_ced(card);
+ rc = mspro_block_switch_interface(card);
if (rc)
return rc;
+
dev_dbg(&card->dev, "card activated\n");
if (msb->system != MEMSTICK_SYS_SERIAL)
msb->caps |= MEMSTICK_CAP_AUTO_GET_INT;
@@ -1127,8 +1189,8 @@ static int mspro_block_init_disk(struct memstick_dev *card)
u64 limit = BLK_BOUNCE_HIGH;
unsigned long capacity;
- if (host->cdev.dev->dma_mask && *(host->cdev.dev->dma_mask))
- limit = *(host->cdev.dev->dma_mask);
+ if (host->dev.dma_mask && *(host->dev.dma_mask))
+ limit = *(host->dev.dma_mask);
for (rc = 0; msb->attr_group.attrs[rc]; ++rc) {
s_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[rc]);
@@ -1148,47 +1210,35 @@ 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 (disk_id < 0)
+ return disk_id;
- if (rc)
- return rc;
-
- if ((disk_id << MEMSTICK_PART_SHIFT) > 255) {
- rc = -ENOSPC;
- goto out_release_id;
- }
-
- msb->disk = alloc_disk(1 << MEMSTICK_PART_SHIFT);
+ msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT);
if (!msb->disk) {
rc = -ENOMEM;
goto out_release_id;
}
- spin_lock_init(&msb->q_lock);
- init_waitqueue_head(&msb->q_wait);
-
- msb->queue = blk_init_queue(mspro_block_request, &msb->q_lock);
+ msb->queue = blk_init_queue(mspro_block_submit_req, &msb->q_lock);
if (!msb->queue) {
rc = -ENOMEM;
goto out_put_disk;
}
msb->queue->queuedata = 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);
msb->disk->major = major;
- msb->disk->first_minor = disk_id << MEMSTICK_PART_SHIFT;
+ msb->disk->first_minor = disk_id << MSPRO_BLOCK_PART_SHIFT;
msb->disk->fops = &ms_block_bdops;
msb->usage_count = 1;
msb->disk->private_data = msb;
@@ -1197,21 +1247,15 @@ 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);
capacity *= msb->page_size >> 9;
set_capacity(msb->disk, capacity);
dev_dbg(&card->dev, "capacity set %ld\n", capacity);
- msb->q_thread = kthread_run(mspro_block_queue_thread, card,
- DRIVER_NAME"d");
- if (IS_ERR(msb->q_thread))
- goto out_put_disk;
- mutex_unlock(&host->lock);
add_disk(msb->disk);
- mutex_lock(&host->lock);
msb->active = 1;
return 0;
@@ -1259,6 +1303,7 @@ static int mspro_block_probe(struct memstick_dev *card)
return -ENOMEM;
memstick_set_drvdata(card, msb);
msb->card = card;
+ spin_lock_init(&msb->q_lock);
rc = mspro_block_init_card(card);
@@ -1272,6 +1317,8 @@ static int mspro_block_probe(struct memstick_dev *card)
rc = mspro_block_init_disk(card);
if (!rc) {
card->check = mspro_block_check_card;
+ card->stop = mspro_block_stop;
+ card->start = mspro_block_start;
return 0;
}
@@ -1286,26 +1333,18 @@ out_free:
static void mspro_block_remove(struct memstick_dev *card)
{
struct mspro_block_data *msb = memstick_get_drvdata(card);
- struct task_struct *q_thread = NULL;
unsigned long flags;
- del_gendisk(msb->disk);
- dev_dbg(&card->dev, "mspro block remove\n");
spin_lock_irqsave(&msb->q_lock, flags);
- q_thread = msb->q_thread;
- msb->q_thread = NULL;
- msb->active = 0;
+ msb->eject = 1;
+ blk_start_queue(msb->queue);
spin_unlock_irqrestore(&msb->q_lock, flags);
- if (q_thread) {
- mutex_unlock(&card->host->lock);
- kthread_stop(q_thread);
- mutex_lock(&card->host->lock);
- }
-
- dev_dbg(&card->dev, "queue thread stopped\n");
+ del_gendisk(msb->disk);
+ dev_dbg(&card->dev, "mspro block remove\n");
blk_cleanup_queue(msb->queue);
+ msb->queue = NULL;
sysfs_remove_group(&card->dev.kobj, &msb->attr_group);
@@ -1322,19 +1361,13 @@ static void mspro_block_remove(struct memstick_dev *card)
static int mspro_block_suspend(struct memstick_dev *card, pm_message_t state)
{
struct mspro_block_data *msb = memstick_get_drvdata(card);
- struct task_struct *q_thread = NULL;
unsigned long flags;
spin_lock_irqsave(&msb->q_lock, flags);
- q_thread = msb->q_thread;
- msb->q_thread = NULL;
- msb->active = 0;
blk_stop_queue(msb->queue);
+ msb->active = 0;
spin_unlock_irqrestore(&msb->q_lock, flags);
- if (q_thread)
- kthread_stop(q_thread);
-
return 0;
}
@@ -1373,14 +1406,7 @@ static int mspro_block_resume(struct memstick_dev *card)
if (memcmp(s_attr->data, r_attr->data, s_attr->size))
break;
- memstick_set_drvdata(card, msb);
- msb->q_thread = kthread_run(mspro_block_queue_thread,
- card, DRIVER_NAME"d");
- if (IS_ERR(msb->q_thread))
- msb->q_thread = NULL;
- else
- msb->active = 1;
-
+ msb->active = 1;
break;
}
}
@@ -1409,7 +1435,7 @@ out_unlock:
static struct memstick_device_id mspro_block_id_tbl[] = {
{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO,
- MEMSTICK_CLASS_GENERIC_DUO},
+ MEMSTICK_CLASS_DUO},
{}
};