block.c revision 548d2de9bd978a4d4e941477500f1ab97aade137
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 246fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale brq.cmd.arg = req->sector; 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; 25408846698703dedae6c6915eb4b4d0a36188c5635Pierre Ossman brq.data.blocks = req->nr_sectors; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2566a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter /* 257548d2de9bd978a4d4e941477500f1ab97aade137Pierre Ossman * The block layer doesn't support all sector count 258548d2de9bd978a4d4e941477500f1ab97aade137Pierre Ossman * restrictions, so we need to be prepared for too big 259548d2de9bd978a4d4e941477500f1ab97aade137Pierre Ossman * requests. 260548d2de9bd978a4d4e941477500f1ab97aade137Pierre Ossman */ 261548d2de9bd978a4d4e941477500f1ab97aade137Pierre Ossman if (brq.data.blocks > card->host->max_blk_count) 262548d2de9bd978a4d4e941477500f1ab97aade137Pierre Ossman brq.data.blocks = card->host->max_blk_count; 263548d2de9bd978a4d4e941477500f1ab97aade137Pierre Ossman 264548d2de9bd978a4d4e941477500f1ab97aade137Pierre Ossman /* 2656a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter * After a read error, we redo the request one sector at a time 2666a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter * in order to accurately determine which sectors can be read 2676a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter * successfully. 2686a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter */ 2696a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (disable_multi && brq.data.blocks > 1) 2706a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter brq.data.blocks = 1; 2716a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter 272788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King if (brq.data.blocks > 1) { 2737213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell /* SPI multiblock writes terminate using a special 2747213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell * token, not a STOP_TRANSMISSION request. 2757213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell */ 2767213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell if (!mmc_host_is_spi(card->host) 2777213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell || rq_data_dir(req) == READ) 2787213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell brq.mrq.stop = &brq.stop; 279db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King readcmd = MMC_READ_MULTIPLE_BLOCK; 280db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King writecmd = MMC_WRITE_MULTIPLE_BLOCK; 281788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King } else { 282788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King brq.mrq.stop = NULL; 283db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King readcmd = MMC_READ_SINGLE_BLOCK; 284db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King writecmd = MMC_WRITE_BLOCK; 285db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King } 286db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King 287db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King if (rq_data_dir(req) == READ) { 288db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King brq.cmd.opcode = readcmd; 289db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King brq.data.flags |= MMC_DATA_READ; 290db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King } else { 291db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King brq.cmd.opcode = writecmd; 292db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King brq.data.flags |= MMC_DATA_WRITE; 293788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King } 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 295b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossman mmc_set_data_timeout(&brq.data, card); 296b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossman 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brq.data.sg = mq->sg; 29898ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman brq.data.sg_len = mmc_queue_map_sg(mq); 29998ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman 3006a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter /* 3016a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter * Adjust the sg list so it is the same size as the 3026a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter * request. 3036a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter */ 3046a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (brq.data.blocks != req->nr_sectors) { 3056a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter int i, data_size = brq.data.blocks << 9; 3066a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter struct scatterlist *sg; 3076a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter 3086a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) { 3096a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter data_size -= sg->length; 3106a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (data_size <= 0) { 3116a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter sg->length += data_size; 3126a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter i++; 3136a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter break; 3146a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter } 3156a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter } 3166a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter brq.data.sg_len = i; 3176a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter } 3186a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter 31998ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman mmc_queue_bounce_pre(mq); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_wait_for_req(card->host, &brq.mrq); 32298ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman 32398ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman mmc_queue_bounce_post(mq); 32498ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman 325979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman /* 326979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman * Check for errors here, but don't jump to cmd_err 327979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman * until later as we need to wait for the card to leave 328979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman * programming mode even when things go wrong. 329979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman */ 3306a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (brq.cmd.error || brq.data.error || brq.stop.error) { 3316a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (brq.data.blocks > 1 && rq_data_dir(req) == READ) { 3326a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter /* Redo read one sector at a time */ 3336a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter printk(KERN_WARNING "%s: retrying using single " 3346a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter "block read\n", req->rq_disk->disk_name); 3356a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter disable_multi = 1; 3366a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter continue; 3376a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter } 338504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter status = get_card_status(card, req); 3396a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter } 340504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (brq.cmd.error) { 342504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter printk(KERN_ERR "%s: error %d sending read/write " 343504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter "command, response %#x, card status %#x\n", 344504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter req->rq_disk->disk_name, brq.cmd.error, 345504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter brq.cmd.resp[0], status); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (brq.data.error) { 349504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter if (brq.data.error == -ETIMEDOUT && brq.mrq.stop) 350504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter /* 'Stop' response contains card status */ 351504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter status = brq.mrq.stop->resp[0]; 352504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter printk(KERN_ERR "%s: error %d transferring data," 353504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter " sector %u, nr %u, card status %#x\n", 354504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter req->rq_disk->disk_name, brq.data.error, 355504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter (unsigned)req->sector, 356504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter (unsigned)req->nr_sectors, status); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (brq.stop.error) { 360504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter printk(KERN_ERR "%s: error %d sending stop command, " 361504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter "response %#x, card status %#x\n", 362504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter req->rq_disk->disk_name, brq.stop.error, 363504f191f25b1671802246bac06c9f59f94f0b7deAdrian Hunter brq.stop.resp[0], status); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3667213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { 3672ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King do { 3682ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King int err; 3692ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King 3702ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King cmd.opcode = MMC_SEND_STATUS; 3712ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King cmd.arg = card->rca << 16; 3722ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 3732ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King err = mmc_wait_for_cmd(card->host, &cmd, 5); 3742ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King if (err) { 3752ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King printk(KERN_ERR "%s: error %d requesting status\n", 3762ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King req->rq_disk->disk_name, err); 3772ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King goto cmd_err; 3782ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King } 379d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman /* 380d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman * Some cards mishandle the status bits, 381d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman * so make sure to check both the busy 382d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman * indication and the card state. 383d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman */ 384d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || 385d198f101989d9bb950327f0d043f6203bb862343Pierre Ossman (R1_CURRENT_STATE(cmd.resp[0]) == 7)); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 3882ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King if (cmd.resp[0] & ~0x00000900) 3892ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King printk(KERN_ERR "%s: status = %08x\n", 3902ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King req->rq_disk->disk_name, cmd.resp[0]); 3912ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King if (mmc_decode_status(cmd.resp)) 3922ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King goto cmd_err; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3942ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King } 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3966a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (brq.cmd.error || brq.stop.error || brq.data.error) { 3976a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (rq_data_dir(req) == READ) { 3986a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter /* 3996a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter * After an error, we redo I/O one sector at a 4006a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter * time, so we only reach here after trying to 4016a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter * read a single sector. 4026a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter */ 4036a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter spin_lock_irq(&md->lock); 4046a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter ret = __blk_end_request(req, -EIO, brq.data.blksz); 4056a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter spin_unlock_irq(&md->lock); 4066a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter continue; 4076a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter } 408979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman goto cmd_err; 4096a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter } 410979ce7208a679b8d012450610d5d5aa75aab3af9Pierre Ossman 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A block was successfully transferred. 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&md->lock); 415fd539832c7d3a242269374dbcae2cd54da150930Kiyoshi Ueda ret = __blk_end_request(req, 0, brq.data.bytes_xfered); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&md->lock); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (ret); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 419b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_release_host(card->host); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd_err: 424ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman /* 425ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * If this is an SD card and we're writing, we can first 426ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * mark the known good sectors as ok. 427ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * 428ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * If the card is not SD, we can still ok written sectors 42923af60398af2f5033e2f53665538a09f498dbc03Pierre Ossman * as reported by the controller (which might be less than 43023af60398af2f5033e2f53665538a09f498dbc03Pierre Ossman * the real number of written sectors, but never more). 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4326a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (mmc_card_sd(card)) { 4336a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter u32 blocks; 43423af60398af2f5033e2f53665538a09f498dbc03Pierre Ossman 4356a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter blocks = mmc_sd_num_wr_blocks(card); 4366a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter if (blocks != (u32)-1) { 437ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman spin_lock_irq(&md->lock); 4386a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter ret = __blk_end_request(req, 0, blocks << 9); 439ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman spin_unlock_irq(&md->lock); 440ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman } 4416a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter } else { 4426a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter spin_lock_irq(&md->lock); 4436a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter ret = __blk_end_request(req, 0, brq.data.bytes_xfered); 4446a79e391df295bd7c2aa1309ea5031f361c197fdAdrian Hunter spin_unlock_irq(&md->lock); 445176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman } 446176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman 447b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_release_host(card->host); 448ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&md->lock); 450fd539832c7d3a242269374dbcae2cd54da150930Kiyoshi Ueda while (ret) 451fd539832c7d3a242269374dbcae2cd54da150930Kiyoshi Ueda ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&md->lock); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 458a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell Kingstatic inline int mmc_blk_readonly(struct mmc_card *card) 459a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King{ 460a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King return mmc_card_readonly(card) || 461a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King !(card->csd.cmdclass & CCC_BLOCK_WRITE); 462a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King} 463a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int devidx, ret; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devidx >= MMC_NUM_MINORS) 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOSPC); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __set_bit(devidx, dev_use); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 474dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); 475a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King if (!md) { 476a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King ret = -ENOMEM; 477a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King goto out; 478a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King } 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King /* 482a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * Set the read-only status based on the supported commands 483a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * and the write protect switch. 484a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King */ 485a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->read_only = mmc_blk_readonly(card); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 487a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk = alloc_disk(1 << MMC_SHIFT); 488a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King if (md->disk == NULL) { 489a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King ret = -ENOMEM; 490a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King goto err_kfree; 491a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 493a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King spin_lock_init(&md->lock); 494a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->usage = 1; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 496a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King ret = mmc_init_queue(&md->queue, card, &md->lock); 497a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King if (ret) 498a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King goto err_putdisk; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 500a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->queue.issue_fn = mmc_blk_issue_rq; 501a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->queue.data = md; 502d2b18394259ef621fd2a6322aa9934198fd87a6aRussell King 503fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman md->disk->major = MMC_BLOCK_MAJOR; 504a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->first_minor = devidx << MMC_SHIFT; 505a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->fops = &mmc_bdops; 506a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->private_data = md; 507a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->queue = md->queue.queue; 508a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->driverfs_dev = &card->dev; 509a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 510a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King /* 511a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * As discussed on lkml, GENHD_FL_REMOVABLE should: 512a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * 513a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * - be set for removable media with permanent block devices 514a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * - be unset for removable block devices with permanent media 515a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * 516a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * Since MMC block devices clearly fall under the second 517a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * case, we do not set GENHD_FL_REMOVABLE. Userspace 518a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * should use the block device creation/destruction hotplug 519a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * messages to tell when the card is present. 520a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King */ 521a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 522a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King sprintf(md->disk->disk_name, "mmcblk%d", devidx); 523a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 52408846698703dedae6c6915eb4b4d0a36188c5635Pierre Ossman blk_queue_hardsect_size(md->queue.queue, 512); 525a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 52685a18ad93ec66888d85758630019b10a84257f3cPierre Ossman if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { 52785a18ad93ec66888d85758630019b10a84257f3cPierre Ossman /* 52885a18ad93ec66888d85758630019b10a84257f3cPierre Ossman * The EXT_CSD sector count is in number or 512 byte 52985a18ad93ec66888d85758630019b10a84257f3cPierre Ossman * sectors. 53085a18ad93ec66888d85758630019b10a84257f3cPierre Ossman */ 53185a18ad93ec66888d85758630019b10a84257f3cPierre Ossman set_capacity(md->disk, card->ext_csd.sectors); 53285a18ad93ec66888d85758630019b10a84257f3cPierre Ossman } else { 53385a18ad93ec66888d85758630019b10a84257f3cPierre Ossman /* 53485a18ad93ec66888d85758630019b10a84257f3cPierre Ossman * The CSD capacity field is in units of read_blkbits. 53585a18ad93ec66888d85758630019b10a84257f3cPierre Ossman * set_capacity takes units of 512 bytes. 53685a18ad93ec66888d85758630019b10a84257f3cPierre Ossman */ 53785a18ad93ec66888d85758630019b10a84257f3cPierre Ossman set_capacity(md->disk, 53885a18ad93ec66888d85758630019b10a84257f3cPierre Ossman card->csd.capacity << (card->csd.read_blkbits - 9)); 53985a18ad93ec66888d85758630019b10a84257f3cPierre Ossman } 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return md; 541a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 542a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King err_putdisk: 543a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King put_disk(md->disk); 544a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King err_kfree: 545a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King kfree(md); 546a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King out: 547a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King return ERR_PTR(ret); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command cmd; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 556fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */ 557fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale if (mmc_card_blockaddr(card)) 558fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale return 0; 559fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale 560b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_claim_host(card->host); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd.opcode = MMC_SET_BLOCKLEN; 56208846698703dedae6c6915eb4b4d0a36188c5635Pierre Ossman cmd.arg = 512; 5637213d175e3b6f6db60f843b72e88857a350e146aDavid Brownell cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = mmc_wait_for_cmd(card->host, &cmd, 5); 565b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_release_host(card->host); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: unable to set block size to %d: %d\n", 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->disk->disk_name, cmd.arg, err); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_probe(struct mmc_card *card) 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md; 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman char cap_str[10]; 582a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman 583912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman /* 584912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman * Check that the card supports the command class(es) we need. 585912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman */ 586912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman if (!(card->csd.cmdclass & CCC_BLOCK_READ)) 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = mmc_blk_alloc(card); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(md)) 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PTR_ERR(md); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = mmc_blk_set_blksize(md, card); 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 597444122fd58fdc83c96877a92b3f6288cafddb08dYi Li string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, 598a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman cap_str, sizeof(cap_str)); 599a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman printk(KERN_INFO "%s: %s %s %s %s\n", 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), 601a7bbb57333447d0cf950992653b6b079585f3531Pierre Ossman cap_str, md->read_only ? "(ro)" : ""); 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_set_drvdata(card, md); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_disk(md->disk); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_blk_put(md); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmc_blk_remove(struct mmc_card *card) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md = mmc_get_drvdata(card); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md) { 61889b4e133afea9fce333054b94d89953583a55c19Pierre Ossman /* Stop new requests from getting into the queue */ 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_gendisk(md->disk); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62189b4e133afea9fce333054b94d89953583a55c19Pierre Ossman /* Then flush out any already in there */ 62289b4e133afea9fce333054b94d89953583a55c19Pierre Ossman mmc_cleanup_queue(&md->queue); 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_blk_put(md); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_set_drvdata(card, NULL); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_suspend(struct mmc_card *card, pm_message_t state) 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md = mmc_get_drvdata(card); 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md) { 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_queue_suspend(&md->queue); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_resume(struct mmc_card *card) 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md = mmc_get_drvdata(card); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md) { 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_blk_set_blksize(md, card); 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_queue_resume(&md->queue); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmc_blk_suspend NULL 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmc_blk_resume NULL 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_driver mmc_driver = { 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "mmcblk", 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = mmc_blk_probe, 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = mmc_blk_remove, 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .suspend = mmc_blk_suspend, 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .resume = mmc_blk_resume, 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init mmc_blk_init(void) 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6679d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita int res; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 669fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); 670fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman if (res) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6739d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita res = mmc_register_driver(&mmc_driver); 6749d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita if (res) 6759d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita goto out2; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6779d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita return 0; 6789d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita out2: 6799d4e98e9609bc19d4a8ac4a5c3218358d1820114Akinobu Mita unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit mmc_blk_exit(void) 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_unregister_driver(&mmc_driver); 687fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mmc_blk_init); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mmc_blk_exit); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Multimedia Card (MMC) block device driver"); 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 696