|
@@ -54,6 +54,7 @@ struct mmc_blk_data {
|
|
|
|
|
|
unsigned int usage;
|
|
|
unsigned int block_bits;
|
|
|
+ unsigned int read_only;
|
|
|
};
|
|
|
|
|
|
static DECLARE_MUTEX(open_lock);
|
|
@@ -85,12 +86,6 @@ static void mmc_blk_put(struct mmc_blk_data *md)
|
|
|
up(&open_lock);
|
|
|
}
|
|
|
|
|
|
-static inline int mmc_blk_readonly(struct mmc_card *card)
|
|
|
-{
|
|
|
- return mmc_card_readonly(card) ||
|
|
|
- !(card->csd.cmdclass & CCC_BLOCK_WRITE);
|
|
|
-}
|
|
|
-
|
|
|
static int mmc_blk_open(struct inode *inode, struct file *filp)
|
|
|
{
|
|
|
struct mmc_blk_data *md;
|
|
@@ -102,8 +97,7 @@ static int mmc_blk_open(struct inode *inode, struct file *filp)
|
|
|
check_disk_change(inode->i_bdev);
|
|
|
ret = 0;
|
|
|
|
|
|
- if ((filp->f_mode & FMODE_WRITE) &&
|
|
|
- mmc_blk_readonly(md->queue.card))
|
|
|
+ if ((filp->f_mode & FMODE_WRITE) && md->read_only)
|
|
|
ret = -EROFS;
|
|
|
}
|
|
|
|
|
@@ -299,6 +293,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|
|
|
|
|
static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
|
|
|
|
|
|
+static inline int mmc_blk_readonly(struct mmc_card *card)
|
|
|
+{
|
|
|
+ return mmc_card_readonly(card) ||
|
|
|
+ !(card->csd.cmdclass & CCC_BLOCK_WRITE);
|
|
|
+}
|
|
|
+
|
|
|
static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
|
|
|
{
|
|
|
struct mmc_blk_data *md;
|
|
@@ -310,64 +310,121 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
|
|
|
__set_bit(devidx, dev_use);
|
|
|
|
|
|
md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
|
|
|
- if (md) {
|
|
|
- memset(md, 0, sizeof(struct mmc_blk_data));
|
|
|
+ if (!md) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
- md->disk = alloc_disk(1 << MMC_SHIFT);
|
|
|
- if (md->disk == NULL) {
|
|
|
- kfree(md);
|
|
|
- md = ERR_PTR(-ENOMEM);
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ memset(md, 0, sizeof(struct mmc_blk_data));
|
|
|
|
|
|
- spin_lock_init(&md->lock);
|
|
|
- md->usage = 1;
|
|
|
+ /*
|
|
|
+ * Set the read-only status based on the supported commands
|
|
|
+ * and the write protect switch.
|
|
|
+ */
|
|
|
+ md->read_only = mmc_blk_readonly(card);
|
|
|
|
|
|
- ret = mmc_init_queue(&md->queue, card, &md->lock);
|
|
|
- if (ret) {
|
|
|
- put_disk(md->disk);
|
|
|
- kfree(md);
|
|
|
- md = ERR_PTR(ret);
|
|
|
- goto out;
|
|
|
+ /*
|
|
|
+ * Figure out a workable block size. MMC cards have:
|
|
|
+ * - two block sizes, one for read and one for write.
|
|
|
+ * - may support partial reads and/or writes
|
|
|
+ * (allows block sizes smaller than specified)
|
|
|
+ */
|
|
|
+ md->block_bits = card->csd.read_blkbits;
|
|
|
+ if (card->csd.write_blkbits != card->csd.read_blkbits) {
|
|
|
+ if (card->csd.write_blkbits < card->csd.read_blkbits &&
|
|
|
+ card->csd.read_partial) {
|
|
|
+ /*
|
|
|
+ * write block size is smaller than read block
|
|
|
+ * size, but we support partial reads, so choose
|
|
|
+ * the smaller write block size.
|
|
|
+ */
|
|
|
+ md->block_bits = card->csd.write_blkbits;
|
|
|
+ } else if (card->csd.write_blkbits > card->csd.read_blkbits &&
|
|
|
+ card->csd.write_partial) {
|
|
|
+ /*
|
|
|
+ * read block size is smaller than write block
|
|
|
+ * size, but we support partial writes. Use read
|
|
|
+ * block size.
|
|
|
+ */
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * We don't support this configuration for writes.
|
|
|
+ */
|
|
|
+ printk(KERN_ERR "%s: unable to select block size for "
|
|
|
+ "writing (rb%u wb%u rp%u wp%u)\n",
|
|
|
+ md->disk->disk_name,
|
|
|
+ 1 << card->csd.read_blkbits,
|
|
|
+ 1 << card->csd.write_blkbits,
|
|
|
+ card->csd.read_partial,
|
|
|
+ card->csd.write_partial);
|
|
|
+ md->read_only = 1;
|
|
|
}
|
|
|
- md->queue.prep_fn = mmc_blk_prep_rq;
|
|
|
- md->queue.issue_fn = mmc_blk_issue_rq;
|
|
|
- md->queue.data = md;
|
|
|
+ }
|
|
|
|
|
|
- md->disk->major = major;
|
|
|
- md->disk->first_minor = devidx << MMC_SHIFT;
|
|
|
- md->disk->fops = &mmc_bdops;
|
|
|
- md->disk->private_data = md;
|
|
|
- md->disk->queue = md->queue.queue;
|
|
|
- md->disk->driverfs_dev = &card->dev;
|
|
|
+ /*
|
|
|
+ * Refuse to allow block sizes smaller than 512 bytes.
|
|
|
+ */
|
|
|
+ if (md->block_bits < 9) {
|
|
|
+ printk(KERN_ERR "%s: unable to support block size %u\n",
|
|
|
+ mmc_card_id(card), 1 << md->block_bits);
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto err_kfree;
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
- * As discussed on lkml, GENHD_FL_REMOVABLE should:
|
|
|
- *
|
|
|
- * - be set for removable media with permanent block devices
|
|
|
- * - be unset for removable block devices with permanent media
|
|
|
- *
|
|
|
- * Since MMC block devices clearly fall under the second
|
|
|
- * case, we do not set GENHD_FL_REMOVABLE. Userspace
|
|
|
- * should use the block device creation/destruction hotplug
|
|
|
- * messages to tell when the card is present.
|
|
|
- */
|
|
|
+ md->disk = alloc_disk(1 << MMC_SHIFT);
|
|
|
+ if (md->disk == NULL) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err_kfree;
|
|
|
+ }
|
|
|
|
|
|
- sprintf(md->disk->disk_name, "mmcblk%d", devidx);
|
|
|
- sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
|
|
|
+ spin_lock_init(&md->lock);
|
|
|
+ md->usage = 1;
|
|
|
|
|
|
- md->block_bits = card->csd.read_blkbits;
|
|
|
+ ret = mmc_init_queue(&md->queue, card, &md->lock);
|
|
|
+ if (ret)
|
|
|
+ goto err_putdisk;
|
|
|
|
|
|
- blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
|
|
|
+ md->queue.prep_fn = mmc_blk_prep_rq;
|
|
|
+ md->queue.issue_fn = mmc_blk_issue_rq;
|
|
|
+ md->queue.data = md;
|
|
|
|
|
|
- /*
|
|
|
- * The CSD capacity field is in units of read_blkbits.
|
|
|
- * set_capacity takes units of 512 bytes.
|
|
|
- */
|
|
|
- set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9));
|
|
|
- }
|
|
|
- out:
|
|
|
+ md->disk->major = major;
|
|
|
+ md->disk->first_minor = devidx << MMC_SHIFT;
|
|
|
+ md->disk->fops = &mmc_bdops;
|
|
|
+ md->disk->private_data = md;
|
|
|
+ md->disk->queue = md->queue.queue;
|
|
|
+ md->disk->driverfs_dev = &card->dev;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * As discussed on lkml, GENHD_FL_REMOVABLE should:
|
|
|
+ *
|
|
|
+ * - be set for removable media with permanent block devices
|
|
|
+ * - be unset for removable block devices with permanent media
|
|
|
+ *
|
|
|
+ * Since MMC block devices clearly fall under the second
|
|
|
+ * case, we do not set GENHD_FL_REMOVABLE. Userspace
|
|
|
+ * should use the block device creation/destruction hotplug
|
|
|
+ * messages to tell when the card is present.
|
|
|
+ */
|
|
|
+
|
|
|
+ sprintf(md->disk->disk_name, "mmcblk%d", devidx);
|
|
|
+ sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
|
|
|
+
|
|
|
+ blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The CSD capacity field is in units of read_blkbits.
|
|
|
+ * set_capacity takes units of 512 bytes.
|
|
|
+ */
|
|
|
+ set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9));
|
|
|
return md;
|
|
|
+
|
|
|
+ err_putdisk:
|
|
|
+ put_disk(md->disk);
|
|
|
+ err_kfree:
|
|
|
+ kfree(md);
|
|
|
+ out:
|
|
|
+ return ERR_PTR(ret);
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -403,12 +460,6 @@ static int mmc_blk_probe(struct mmc_card *card)
|
|
|
if (!(card->csd.cmdclass & CCC_BLOCK_READ))
|
|
|
return -ENODEV;
|
|
|
|
|
|
- if (card->csd.read_blkbits < 9) {
|
|
|
- printk(KERN_WARNING "%s: read blocksize too small (%u)\n",
|
|
|
- mmc_card_id(card), 1 << card->csd.read_blkbits);
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
-
|
|
|
md = mmc_blk_alloc(card);
|
|
|
if (IS_ERR(md))
|
|
|
return PTR_ERR(md);
|
|
@@ -419,7 +470,7 @@ static int mmc_blk_probe(struct mmc_card *card)
|
|
|
|
|
|
printk(KERN_INFO "%s: %s %s %luKiB %s\n",
|
|
|
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
|
|
|
- get_capacity(md->disk) >> 1, mmc_blk_readonly(card)?"(ro)":"");
|
|
|
+ get_capacity(md->disk) >> 1, md->read_only ? "(ro)" : "");
|
|
|
|
|
|
mmc_set_drvdata(card, md);
|
|
|
add_disk(md->disk);
|