block.c revision 83096ebf1263b2c1ee5e653ba37d993d02e3eb7b
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Block driver for media (i.e., flash cards)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2002 Hewlett-Packard Company
5979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman * Copyright 2005-2008 Pierre Ossman
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use consistent with the GNU GPL is permitted,
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provided that this copyright notice is
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * preserved in its entirety in all copies and derived works.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FITNESS FOR ANY PARTICULAR PURPOSE.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Many thanks to Alessandro Rubini and Jonathan Corbet!
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author:  Andrew Christian
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *          28 May 2002
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdreg.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kdev_t.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
30a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven#include <linux/mutex.h>
31ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman#include <linux/scatterlist.h>
32a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman#include <linux/string_helpers.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/card.h>
35385e3227d4d83ab13d7767c4bb3593b0256bf246Pierre Ossman#include <linux/mmc/host.h>
36da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/mmc.h>
37da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/sd.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4298ac2162699f7e9880683cb954891817f20b607cPierre Ossman#include "queue.h"
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
446b0b62853b2553be375033776902640320970846Andy WhitcroftMODULE_ALIAS("mmc:block");
456b0b62853b2553be375033776902640320970846Andy Whitcroft
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * max 8 partitions per card
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MMC_SHIFT	3
501dff314451fa24d6b107aa05393d3169e56a7e0aDavid Woodhouse#define MMC_NUM_MINORS	(256 >> MMC_SHIFT)
511dff314451fa24d6b107aa05393d3169e56a7e0aDavid Woodhouse
52203c80187eba037f2d6562e0d5847014746726ddBen Collinsstatic DECLARE_BITMAP(dev_use, MMC_NUM_MINORS);
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is one mmc_blk_data per slot.
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mmc_blk_data {
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t	lock;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gendisk	*disk;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_queue queue;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int	usage;
63a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	unsigned int	read_only;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
66a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Venstatic DEFINE_MUTEX(open_lock);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_blk_data *md;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
72a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven	mutex_lock(&open_lock);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	md = disk->private_data;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md && md->usage == 0)
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		md = NULL;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		md->usage++;
78a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven	mutex_unlock(&open_lock);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return md;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmc_blk_put(struct mmc_blk_data *md)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
85a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven	mutex_lock(&open_lock);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	md->usage--;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md->usage == 0) {
88f331c0296f2a9fee0d396a70598b954062603015Tejun Heo		int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
891dff314451fa24d6b107aa05393d3169e56a7e0aDavid Woodhouse		__clear_bit(devidx, dev_use);
901dff314451fa24d6b107aa05393d3169e56a7e0aDavid Woodhouse
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		put_disk(md->disk);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(md);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
94a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven	mutex_unlock(&open_lock);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
97a5a1561f88fe8bfd7fdceed1d942ad494500b8a9Al Virostatic int mmc_blk_open(struct block_device *bdev, fmode_t mode)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
99a5a1561f88fe8bfd7fdceed1d942ad494500b8a9Al Viro	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = -ENXIO;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md) {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (md->usage == 2)
104a5a1561f88fe8bfd7fdceed1d942ad494500b8a9Al Viro			check_disk_change(bdev);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
106a00fc09029f02ca833cf90e5d5625f08c4ac4f51Pierre Ossman
107a5a1561f88fe8bfd7fdceed1d942ad494500b8a9Al Viro		if ((mode & FMODE_WRITE) && md->read_only) {
10870bb08962ea9bd50797ae9f16b2493f5f7c65053Andrew Morton			mmc_blk_put(md);
109a00fc09029f02ca833cf90e5d5625f08c4ac4f51Pierre Ossman			ret = -EROFS;
11070bb08962ea9bd50797ae9f16b2493f5f7c65053Andrew Morton		}
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
116a5a1561f88fe8bfd7fdceed1d942ad494500b8a9Al Virostatic int mmc_blk_release(struct gendisk *disk, fmode_t mode)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
118a5a1561f88fe8bfd7fdceed1d942ad494500b8a9Al Viro	struct mmc_blk_data *md = disk->private_data;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_blk_put(md);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
125a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwigmmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
127a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
128a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	geo->heads = 4;
129a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	geo->sectors = 16;
130a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	return 0;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct block_device_operations mmc_bdops = {
134a5a1561f88fe8bfd7fdceed1d942ad494500b8a9Al Viro	.open			= mmc_blk_open,
135a5a1561f88fe8bfd7fdceed1d942ad494500b8a9Al Viro	.release		= mmc_blk_release,
136a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	.getgeo			= mmc_blk_getgeo,
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner			= THIS_MODULE,
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mmc_blk_request {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_request	mrq;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_command	cmd;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_command	stop;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_data		data;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
147ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossmanstatic u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
148ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman{
149ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	int err;
150b7a03210b7b381e06f71751cb9addfae7704489cHarvey Harrison	__be32 blocks;
151ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
152ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	struct mmc_request mrq;
153ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	struct mmc_command cmd;
154ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	struct mmc_data data;
155ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	unsigned int timeout_us;
156ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
157ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	struct scatterlist sg;
158ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
159ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	memset(&cmd, 0, sizeof(struct mmc_command));
160ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
161ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	cmd.opcode = MMC_APP_CMD;
162ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	cmd.arg = card->rca << 16;
1637213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
164ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
165ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	err = mmc_wait_for_cmd(card->host, &cmd, 0);
1667213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell	if (err)
1677213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell		return (u32)-1;
1687213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell	if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
169ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman		return (u32)-1;
170ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
171ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	memset(&cmd, 0, sizeof(struct mmc_command));
172ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
173ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
174ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	cmd.arg = 0;
1757213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
176ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
177ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	memset(&data, 0, sizeof(struct mmc_data));
178ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
179ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	data.timeout_ns = card->csd.tacc_ns * 100;
180ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	data.timeout_clks = card->csd.tacc_clks * 100;
181ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
182ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	timeout_us = data.timeout_ns / 1000;
183ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	timeout_us += data.timeout_clks * 1000 /
184ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman		(card->host->ios.clock / 1000);
185ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
186ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	if (timeout_us > 100000) {
187ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman		data.timeout_ns = 100000000;
188ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman		data.timeout_clks = 0;
189ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	}
190ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
191ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	data.blksz = 4;
192ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	data.blocks = 1;
193ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	data.flags = MMC_DATA_READ;
194ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	data.sg = &sg;
195ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	data.sg_len = 1;
196ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
197ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	memset(&mrq, 0, sizeof(struct mmc_request));
198ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
199ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	mrq.cmd = &cmd;
200ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	mrq.data = &data;
201ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
202ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	sg_init_one(&sg, &blocks, 4);
203ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
204ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	mmc_wait_for_req(card->host, &mrq);
205ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
20617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	if (cmd.error || data.error)
207ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman		return (u32)-1;
208ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
209b7a03210b7b381e06f71751cb9addfae7704489cHarvey Harrison	return ntohl(blocks);
210ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman}
211ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
212504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunterstatic u32 get_card_status(struct mmc_card *card, struct request *req)
213504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter{
214504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	struct mmc_command cmd;
215504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	int err;
216504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter
217504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	memset(&cmd, 0, sizeof(struct mmc_command));
218504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	cmd.opcode = MMC_SEND_STATUS;
219504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	if (!mmc_host_is_spi(card->host))
220504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter		cmd.arg = card->rca << 16;
221504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
222504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	err = mmc_wait_for_cmd(card->host, &cmd, 0);
223504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	if (err)
224504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter		printk(KERN_ERR "%s: error %d sending status comand",
225504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter		       req->rq_disk->disk_name, err);
226504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter	return cmd.resp[0];
227504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter}
228504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_blk_data *md = mq->data;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_card *card = md->queue.card;
233176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman	struct mmc_blk_request brq;
2346a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter	int ret = 1, disable_multi = 0;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
236b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman	mmc_claim_host(card->host);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct mmc_command cmd;
240504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter		u32 readcmd, writecmd, status = 0;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(&brq, 0, sizeof(struct mmc_blk_request));
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		brq.mrq.cmd = &brq.cmd;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		brq.mrq.data = &brq.data;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24683096ebf1263b2c1ee5e653ba37d993d02e3eb7bTejun Heo		brq.cmd.arg = blk_rq_pos(req);
247fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale		if (!mmc_card_blockaddr(card))
248fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale			brq.cmd.arg <<= 9;
2497213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
25008846698703dedae6c6915eb4b4d0a36188c5635Pierre Ossman		brq.data.blksz = 512;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		brq.stop.opcode = MMC_STOP_TRANSMISSION;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		brq.stop.arg = 0;
2537213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
25483096ebf1263b2c1ee5e653ba37d993d02e3eb7bTejun Heo		brq.data.blocks = blk_rq_sectors(req);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2566a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		/*
2576a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		 * After a read error, we redo the request one sector at a time
2586a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		 * in order to accurately determine which sectors can be read
2596a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		 * successfully.
2606a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		 */
2616a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		if (disable_multi && brq.data.blocks > 1)
2626a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			brq.data.blocks = 1;
2636a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter
264788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King		if (brq.data.blocks > 1) {
2657213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell			/* SPI multiblock writes terminate using a special
2667213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell			 * token, not a STOP_TRANSMISSION request.
2677213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell			 */
2687213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell			if (!mmc_host_is_spi(card->host)
2697213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell					|| rq_data_dir(req) == READ)
2707213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell				brq.mrq.stop = &brq.stop;
271db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King			readcmd = MMC_READ_MULTIPLE_BLOCK;
272db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King			writecmd = MMC_WRITE_MULTIPLE_BLOCK;
273788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King		} else {
274788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King			brq.mrq.stop = NULL;
275db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King			readcmd = MMC_READ_SINGLE_BLOCK;
276db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King			writecmd = MMC_WRITE_BLOCK;
277db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King		}
278db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King
279db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King		if (rq_data_dir(req) == READ) {
280db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King			brq.cmd.opcode = readcmd;
281db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King			brq.data.flags |= MMC_DATA_READ;
282db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King		} else {
283db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King			brq.cmd.opcode = writecmd;
284db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King			brq.data.flags |= MMC_DATA_WRITE;
285788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King		}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
287b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossman		mmc_set_data_timeout(&brq.data, card);
288b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossman
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		brq.data.sg = mq->sg;
29098ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman		brq.data.sg_len = mmc_queue_map_sg(mq);
29198ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman
2926a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		/*
2936a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		 * Adjust the sg list so it is the same size as the
2946a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		 * request.
2956a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		 */
29683096ebf1263b2c1ee5e653ba37d993d02e3eb7bTejun Heo		if (brq.data.blocks != blk_rq_sectors(req)) {
2976a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			int i, data_size = brq.data.blocks << 9;
2986a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			struct scatterlist *sg;
2996a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter
3006a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
3016a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				data_size -= sg->length;
3026a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				if (data_size <= 0) {
3036a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter					sg->length += data_size;
3046a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter					i++;
3056a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter					break;
3066a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				}
3076a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			}
3086a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			brq.data.sg_len = i;
3096a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		}
3106a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter
31198ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman		mmc_queue_bounce_pre(mq);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_wait_for_req(card->host, &brq.mrq);
31498ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman
31598ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman		mmc_queue_bounce_post(mq);
31698ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman
317979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman		/*
318979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman		 * Check for errors here, but don't jump to cmd_err
319979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman		 * until later as we need to wait for the card to leave
320979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman		 * programming mode even when things go wrong.
321979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman		 */
3226a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		if (brq.cmd.error || brq.data.error || brq.stop.error) {
3236a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
3246a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				/* Redo read one sector at a time */
3256a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				printk(KERN_WARNING "%s: retrying using single "
3266a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				       "block read\n", req->rq_disk->disk_name);
3276a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				disable_multi = 1;
3286a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				continue;
3296a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			}
330504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			status = get_card_status(card, req);
3316a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		}
332504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (brq.cmd.error) {
334504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			printk(KERN_ERR "%s: error %d sending read/write "
335504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			       "command, response %#x, card status %#x\n",
336504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			       req->rq_disk->disk_name, brq.cmd.error,
337504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			       brq.cmd.resp[0], status);
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (brq.data.error) {
341504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			if (brq.data.error == -ETIMEDOUT && brq.mrq.stop)
342504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter				/* 'Stop' response contains card status */
343504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter				status = brq.mrq.stop->resp[0];
344504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			printk(KERN_ERR "%s: error %d transferring data,"
345504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			       " sector %u, nr %u, card status %#x\n",
346504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			       req->rq_disk->disk_name, brq.data.error,
34783096ebf1263b2c1ee5e653ba37d993d02e3eb7bTejun Heo			       (unsigned)blk_rq_pos(req),
34883096ebf1263b2c1ee5e653ba37d993d02e3eb7bTejun Heo			       (unsigned)blk_rq_sectors(req), status);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (brq.stop.error) {
352504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			printk(KERN_ERR "%s: error %d sending stop command, "
353504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			       "response %#x, card status %#x\n",
354504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			       req->rq_disk->disk_name, brq.stop.error,
355504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter			       brq.stop.resp[0], status);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3587213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell		if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
3592ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King			do {
3602ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				int err;
3612ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King
3622ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				cmd.opcode = MMC_SEND_STATUS;
3632ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				cmd.arg = card->rca << 16;
3642ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
3652ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				err = mmc_wait_for_cmd(card->host, &cmd, 5);
3662ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				if (err) {
3672ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King					printk(KERN_ERR "%s: error %d requesting status\n",
3682ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King					       req->rq_disk->disk_name, err);
3692ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King					goto cmd_err;
3702ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				}
371d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman				/*
372d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman				 * Some cards mishandle the status bits,
373d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman				 * so make sure to check both the busy
374d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman				 * indication and the card state.
375d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman				 */
376d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman			} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
377d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman				(R1_CURRENT_STATE(cmd.resp[0]) == 7));
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3802ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King			if (cmd.resp[0] & ~0x00000900)
3812ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				printk(KERN_ERR "%s: status = %08x\n",
3822ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				       req->rq_disk->disk_name, cmd.resp[0]);
3832ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King			if (mmc_decode_status(cmd.resp))
3842ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King				goto cmd_err;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3862ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King		}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3886a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		if (brq.cmd.error || brq.stop.error || brq.data.error) {
3896a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			if (rq_data_dir(req) == READ) {
3906a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				/*
3916a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				 * After an error, we redo I/O one sector at a
3926a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				 * time, so we only reach here after trying to
3936a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				 * read a single sector.
3946a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				 */
3956a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				spin_lock_irq(&md->lock);
3966a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				ret = __blk_end_request(req, -EIO, brq.data.blksz);
3976a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				spin_unlock_irq(&md->lock);
3986a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter				continue;
3996a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			}
400979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman			goto cmd_err;
4016a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		}
402979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * A block was successfully transferred.
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irq(&md->lock);
407fd539832c7d3a242269374dbcae2cd54da150930Kiyoshi Ueda		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irq(&md->lock);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (ret);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman	mmc_release_host(card->host);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd_err:
416ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 	/*
417ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 	 * If this is an SD card and we're writing, we can first
418ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 	 * mark the known good sectors as ok.
419ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 	 *
420ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman	 * If the card is not SD, we can still ok written sectors
42123af60398af2f5033e2f53665538a09f498dbc03Pierre Ossman	 * as reported by the controller (which might be less than
42223af60398af2f5033e2f53665538a09f498dbc03Pierre Ossman	 * the real number of written sectors, but never more).
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4246a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter	if (mmc_card_sd(card)) {
4256a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		u32 blocks;
42623af60398af2f5033e2f53665538a09f498dbc03Pierre Ossman
4276a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		blocks = mmc_sd_num_wr_blocks(card);
4286a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		if (blocks != (u32)-1) {
429ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman			spin_lock_irq(&md->lock);
4306a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter			ret = __blk_end_request(req, 0, blocks << 9);
431ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman			spin_unlock_irq(&md->lock);
432ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman		}
4336a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter	} else {
4346a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		spin_lock_irq(&md->lock);
4356a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
4366a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter		spin_unlock_irq(&md->lock);
437176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman	}
438176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman
439b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman	mmc_release_host(card->host);
440ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&md->lock);
442fd539832c7d3a242269374dbcae2cd54da150930Kiyoshi Ueda	while (ret)
443fd539832c7d3a242269374dbcae2cd54da150930Kiyoshi Ueda		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&md->lock);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
450a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell Kingstatic inline int mmc_blk_readonly(struct mmc_card *card)
451a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King{
452a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	return mmc_card_readonly(card) ||
453a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
454a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King}
455a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_blk_data *md;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int devidx, ret;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (devidx >= MMC_NUM_MINORS)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENOSPC);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__set_bit(devidx, dev_use);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
466dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau	md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
467a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	if (!md) {
468a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King		ret = -ENOMEM;
469a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King		goto out;
470a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
473a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	/*
474a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * Set the read-only status based on the supported commands
475a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * and the write protect switch.
476a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 */
477a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->read_only = mmc_blk_readonly(card);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
479a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->disk = alloc_disk(1 << MMC_SHIFT);
480a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	if (md->disk == NULL) {
481a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King		ret = -ENOMEM;
482a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King		goto err_kfree;
483a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	}
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
485a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	spin_lock_init(&md->lock);
486a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->usage = 1;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
488a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	ret = mmc_init_queue(&md->queue, card, &md->lock);
489a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	if (ret)
490a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King		goto err_putdisk;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
492a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->queue.issue_fn = mmc_blk_issue_rq;
493a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->queue.data = md;
494d2b18394259ef621fd2a6322aa9934198fd87a6aRussell King
495fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman	md->disk->major	= MMC_BLOCK_MAJOR;
496a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->disk->first_minor = devidx << MMC_SHIFT;
497a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->disk->fops = &mmc_bdops;
498a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->disk->private_data = md;
499a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->disk->queue = md->queue.queue;
500a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	md->disk->driverfs_dev = &card->dev;
501a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King
502a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	/*
503a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * As discussed on lkml, GENHD_FL_REMOVABLE should:
504a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 *
505a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * - be set for removable media with permanent block devices
506a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * - be unset for removable block devices with permanent media
507a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 *
508a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * Since MMC block devices clearly fall under the second
509a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * case, we do not set GENHD_FL_REMOVABLE.  Userspace
510a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * should use the block device creation/destruction hotplug
511a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 * messages to tell when the card is present.
512a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	 */
513a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King
514a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
515a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King
51608846698703dedae6c6915eb4b4d0a36188c5635Pierre Ossman	blk_queue_hardsect_size(md->queue.queue, 512);
517a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King
51885a18ad93ec66888d85758630019b10a84257f3cPierre Ossman	if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
51985a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		/*
52085a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		 * The EXT_CSD sector count is in number or 512 byte
52185a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		 * sectors.
52285a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		 */
52385a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		set_capacity(md->disk, card->ext_csd.sectors);
52485a18ad93ec66888d85758630019b10a84257f3cPierre Ossman	} else {
52585a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		/*
52685a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		 * The CSD capacity field is in units of read_blkbits.
52785a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		 * set_capacity takes units of 512 bytes.
52885a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		 */
52985a18ad93ec66888d85758630019b10a84257f3cPierre Ossman		set_capacity(md->disk,
53085a18ad93ec66888d85758630019b10a84257f3cPierre Ossman			card->csd.capacity << (card->csd.read_blkbits - 9));
53185a18ad93ec66888d85758630019b10a84257f3cPierre Ossman	}
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return md;
533a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King
534a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King err_putdisk:
535a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	put_disk(md->disk);
536a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King err_kfree:
537a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	kfree(md);
538a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King out:
539a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King	return ERR_PTR(ret);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_command cmd;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
548fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale	/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
549fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale	if (mmc_card_blockaddr(card))
550fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale		return 0;
551fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale
552b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman	mmc_claim_host(card->host);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd.opcode = MMC_SET_BLOCKLEN;
55408846698703dedae6c6915eb4b4d0a36188c5635Pierre Ossman	cmd.arg = 512;
5557213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = mmc_wait_for_cmd(card->host, &cmd, 5);
557b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman	mmc_release_host(card->host);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err) {
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			md->disk->disk_name, cmd.arg, err);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_probe(struct mmc_card *card)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_blk_data *md;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
573a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman	char cap_str[10];
574a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman
575912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman	/*
576912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman	 * Check that the card supports the command class(es) we need.
577912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman	 */
578912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman	if (!(card->csd.cmdclass & CCC_BLOCK_READ))
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	md = mmc_blk_alloc(card);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(md))
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(md);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = mmc_blk_set_blksize(md, card);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
589444122fd58fdc83c96877a92b3f6288cafddb08dYi Li	string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
590a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman			cap_str, sizeof(cap_str));
591a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman	printk(KERN_INFO "%s: %s %s %s %s\n",
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
593a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman		cap_str, md->read_only ? "(ro)" : "");
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_set_drvdata(card, md);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_disk(md->disk);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_blk_put(md);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmc_blk_remove(struct mmc_card *card)
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_blk_data *md = mmc_get_drvdata(card);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md) {
61089b4e133afea9fce333054b94d89953583a55c19Pierre Ossman		/* Stop new requests from getting into the queue */
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		del_gendisk(md->disk);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61389b4e133afea9fce333054b94d89953583a55c19Pierre Ossman		/* Then flush out any already in there */
61489b4e133afea9fce333054b94d89953583a55c19Pierre Ossman		mmc_cleanup_queue(&md->queue);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_blk_put(md);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_set_drvdata(card, NULL);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_blk_data *md = mmc_get_drvdata(card);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md) {
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_queue_suspend(&md->queue);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_resume(struct mmc_card *card)
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_blk_data *md = mmc_get_drvdata(card);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md) {
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_blk_set_blksize(md, card);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_queue_resume(&md->queue);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	mmc_blk_suspend	NULL
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmc_blk_resume	NULL
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_driver mmc_driver = {
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.drv		= {
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name	= "mmcblk",
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= mmc_blk_probe,
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove		= mmc_blk_remove,
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.suspend	= mmc_blk_suspend,
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.resume		= mmc_blk_resume,
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init mmc_blk_init(void)
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6599d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita	int res;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman	res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
662fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman	if (res)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6659d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita	res = mmc_register_driver(&mmc_driver);
6669d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita	if (res)
6679d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita		goto out2;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6699d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita	return 0;
6709d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita out2:
6719d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita	unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit mmc_blk_exit(void)
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_unregister_driver(&mmc_driver);
679fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman	unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mmc_blk_init);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mmc_blk_exit);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
688