3392 lines · 84.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Block driver for media (i.e., flash cards) * * Copyright 2002 Hewlett-Packard Company * Copyright 2005-2008 Pierre Ossman * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is * preserved in its entirety in all copies and derived works. * * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS * FITNESS FOR ANY PARTICULAR PURPOSE. * * Many thanks to Alessandro Rubini and Jonathan Corbet! * * Author:  Andrew Christian *          28 May 2002 */#include <linux/moduleparam.h>#include <linux/module.h>#include <linux/init.h> #include <linux/kernel.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/hdreg.h>#include <linux/kdev_t.h>#include <linux/kref.h>#include <linux/blkdev.h>#include <linux/cdev.h>#include <linux/mutex.h>#include <linux/scatterlist.h>#include <linux/string.h>#include <linux/string_helpers.h>#include <linux/delay.h>#include <linux/capability.h>#include <linux/compat.h>#include <linux/pm_runtime.h>#include <linux/idr.h>#include <linux/debugfs.h>#include <linux/rpmb.h> #include <linux/mmc/ioctl.h>#include <linux/mmc/card.h>#include <linux/mmc/host.h>#include <linux/mmc/mmc.h>#include <linux/mmc/sd.h> #include <linux/uaccess.h>#include <linux/unaligned.h> #include "queue.h"#include "block.h"#include "core.h"#include "card.h"#include "crypto.h"#include "host.h"#include "bus.h"#include "mmc_ops.h"#include "quirks.h"#include "sd_ops.h" MODULE_ALIAS("mmc:block");#ifdef MODULE_PARAM_PREFIX#undef MODULE_PARAM_PREFIX#endif#define MODULE_PARAM_PREFIX "mmcblk." /* * Set a 10 second timeout for polling write request busy state. Note, mmc core * is setting a 3 second timeout for SD cards, and SDHCI has long had a 10 * second software timer to timeout the whole request, so 10 seconds should be * ample. */#define MMC_BLK_TIMEOUT_MS  (10 * 1000)#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)#define MMC_EXTRACT_VALUE_FROM_ARG(x) ((x & 0x0000FF00) >> 8) #define RPMB_FRAME_SIZE        sizeof(struct rpmb_frame)#define CHECK_SIZE_NEQ(val) ((val) != sizeof(struct rpmb_frame))#define CHECK_SIZE_ALIGNED(val) IS_ALIGNED((val), sizeof(struct rpmb_frame)) static DEFINE_MUTEX(block_mutex); /* * The defaults come from config options but can be overriden by module * or bootarg options. */static int perdev_minors = CONFIG_MMC_BLOCK_MINORS; /* * We've only got one major, so number of mmcblk devices is * limited to (1 << 20) / number of minors per device.  It is also * limited by the MAX_DEVICES below. */static int max_devices; #define MAX_DEVICES 256 static DEFINE_IDA(mmc_blk_ida);static DEFINE_IDA(mmc_rpmb_ida); struct mmc_blk_busy_data {	struct mmc_card *card;	u32 status;}; /* * There is one mmc_blk_data per slot. */struct mmc_blk_data {	struct device	*parent;	struct gendisk	*disk;	struct mmc_queue queue;	struct list_head part;	struct list_head rpmbs; 	unsigned int	flags;#define MMC_BLK_CMD23	(1 << 0)	/* Can do SET_BLOCK_COUNT for multiblock */#define MMC_BLK_REL_WR	(1 << 1)	/* MMC Reliable write support */ 	struct kref	kref;	unsigned int	read_only;	unsigned int	part_type;	unsigned int	reset_done;#define MMC_BLK_READ		BIT(0)#define MMC_BLK_WRITE		BIT(1)#define MMC_BLK_DISCARD		BIT(2)#define MMC_BLK_SECDISCARD	BIT(3)#define MMC_BLK_CQE_RECOVERY	BIT(4)#define MMC_BLK_TRIM		BIT(5) 	/*	 * Only set in main mmc_blk_data associated	 * with mmc_card with dev_set_drvdata, and keeps	 * track of the current selected device partition.	 */	unsigned int	part_curr;#define MMC_BLK_PART_INVALID	UINT_MAX	/* Unknown partition active */	int	area_type; 	/* debugfs files (only in main mmc_blk_data) */	struct dentry *status_dentry;	struct dentry *ext_csd_dentry;}; /* Device type for RPMB character devices */static dev_t mmc_rpmb_devt; /* Bus type for RPMB character devices */static const struct bus_type mmc_rpmb_bus_type = {	.name = "mmc_rpmb",}; /** * struct mmc_rpmb_data - special RPMB device type for these areas * @dev: the device for the RPMB area * @chrdev: character device for the RPMB area * @id: unique device ID number * @part_index: partition index (0 on first) * @md: parent MMC block device * @rdev: registered RPMB device * @node: list item, so we can put this device on a list */struct mmc_rpmb_data {	struct device dev;	struct cdev chrdev;	int id;	unsigned int part_index;	struct mmc_blk_data *md;	struct rpmb_dev *rdev;	struct list_head node;}; static DEFINE_MUTEX(open_lock); module_param(perdev_minors, int, 0444);MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); static inline int mmc_blk_part_switch(struct mmc_card *card,				      unsigned int part_type);static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,			       struct mmc_card *card,			       int recovery_mode,			       struct mmc_queue *mq);static void mmc_blk_hsq_req_done(struct mmc_request *mrq);static int mmc_spi_err_check(struct mmc_card *card);static int mmc_blk_busy_cb(void *cb_data, bool *busy); static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk){	struct mmc_blk_data *md; 	mutex_lock(&open_lock);	md = disk->private_data;	if (md && !kref_get_unless_zero(&md->kref))		md = NULL;	mutex_unlock(&open_lock); 	return md;} static inline int mmc_get_devidx(struct gendisk *disk){	int devidx = disk->first_minor / perdev_minors;	return devidx;} static void mmc_blk_kref_release(struct kref *ref){	struct mmc_blk_data *md = container_of(ref, struct mmc_blk_data, kref);	int devidx; 	devidx = mmc_get_devidx(md->disk);	ida_free(&mmc_blk_ida, devidx); 	mutex_lock(&open_lock);	md->disk->private_data = NULL;	mutex_unlock(&open_lock); 	put_disk(md->disk);	kfree(md);} static void mmc_blk_put(struct mmc_blk_data *md){	kref_put(&md->kref, mmc_blk_kref_release);} static ssize_t power_ro_lock_show(struct device *dev,		struct device_attribute *attr, char *buf){	int ret;	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));	struct mmc_card *card = md->queue.card;	int locked = 0; 	if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)		locked = 2;	else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)		locked = 1; 	ret = sysfs_emit(buf, "%d\n", locked); 	mmc_blk_put(md); 	return ret;} static ssize_t power_ro_lock_store(struct device *dev,		struct device_attribute *attr, const char *buf, size_t count){	int ret;	struct mmc_blk_data *md, *part_md;	struct mmc_queue *mq;	struct request *req;	unsigned long set; 	if (kstrtoul(buf, 0, &set))		return -EINVAL; 	if (set != 1)		return count; 	md = mmc_blk_get(dev_to_disk(dev));	mq = &md->queue; 	/* Dispatch locking to the block layer */	req = blk_mq_alloc_request(mq->queue, REQ_OP_DRV_OUT, 0);	if (IS_ERR(req)) {		count = PTR_ERR(req);		goto out_put;	}	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;	req_to_mmc_queue_req(req)->drv_op_result = -EIO;	blk_execute_rq(req, false);	ret = req_to_mmc_queue_req(req)->drv_op_result;	blk_mq_free_request(req); 	if (!ret) {		pr_info("%s: Locking boot partition ro until next power on\n",			md->disk->disk_name);		set_disk_ro(md->disk, 1); 		list_for_each_entry(part_md, &md->part, part)			if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {				pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name);				set_disk_ro(part_md->disk, 1);			}	}out_put:	mmc_blk_put(md);	return count;} static DEVICE_ATTR(ro_lock_until_next_power_on, 0,		power_ro_lock_show, power_ro_lock_store); static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,			     char *buf){	int ret;	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); 	ret = sysfs_emit(buf, "%d\n",			 get_disk_ro(dev_to_disk(dev)) ^			 md->read_only);	mmc_blk_put(md);	return ret;} static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,			      const char *buf, size_t count){	int ret;	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));	unsigned long set; 	if (kstrtoul(buf, 0, &set)) {		ret = -EINVAL;		goto out;	} 	set_disk_ro(dev_to_disk(dev), set || md->read_only);	ret = count;out:	mmc_blk_put(md);	return ret;} static DEVICE_ATTR(force_ro, 0644, force_ro_show, force_ro_store); static struct attribute *mmc_disk_attrs[] = {	&dev_attr_force_ro.attr,	&dev_attr_ro_lock_until_next_power_on.attr,	NULL,}; static umode_t mmc_disk_attrs_is_visible(struct kobject *kobj,		struct attribute *a, int n){	struct device *dev = kobj_to_dev(kobj);	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));	umode_t mode = a->mode; 	if (a == &dev_attr_ro_lock_until_next_power_on.attr &&	    (md->area_type & MMC_BLK_DATA_AREA_BOOT) &&	    md->queue.card->ext_csd.boot_ro_lockable) {		mode = 0444;		if (!(md->queue.card->ext_csd.boot_ro_lock &				EXT_CSD_BOOT_WP_B_PWR_WP_DIS))			mode |= 0200;	} 	mmc_blk_put(md);	return mode;} static const struct attribute_group mmc_disk_attr_group = {	.is_visible	= mmc_disk_attrs_is_visible,	.attrs		= mmc_disk_attrs,}; static const struct attribute_group *mmc_disk_attr_groups[] = {	&mmc_disk_attr_group,	NULL,}; static int mmc_blk_open(struct gendisk *disk, blk_mode_t mode){	struct mmc_blk_data *md = mmc_blk_get(disk);	int ret = -ENXIO; 	mutex_lock(&block_mutex);	if (md) {		ret = 0;		if ((mode & BLK_OPEN_WRITE) && md->read_only) {			mmc_blk_put(md);			ret = -EROFS;		}	}	mutex_unlock(&block_mutex); 	return ret;} static void mmc_blk_release(struct gendisk *disk){	struct mmc_blk_data *md = disk->private_data; 	mutex_lock(&block_mutex);	mmc_blk_put(md);	mutex_unlock(&block_mutex);} static intmmc_blk_getgeo(struct gendisk *disk, struct hd_geometry *geo){	geo->cylinders = get_capacity(disk) / (4 * 16);	geo->heads = 4;	geo->sectors = 16;	return 0;} struct mmc_blk_ioc_data {	struct mmc_ioc_cmd ic;	unsigned char *buf;	u64 buf_bytes;	unsigned int flags;#define MMC_BLK_IOC_DROP	BIT(0)	/* drop this mrq */#define MMC_BLK_IOC_SBC	BIT(1)	/* use mrq.sbc */ 	struct mmc_rpmb_data *rpmb;}; static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(	struct mmc_ioc_cmd __user *user){	struct mmc_blk_ioc_data *idata;	int err; 	idata = kzalloc_obj(*idata);	if (!idata) {		err = -ENOMEM;		goto out;	} 	if (copy_from_user(&idata->ic, user, sizeof(idata->ic))) {		err = -EFAULT;		goto idata_err;	} 	idata->buf_bytes = (u64) idata->ic.blksz * idata->ic.blocks;	if (idata->buf_bytes > MMC_IOC_MAX_BYTES) {		err = -EOVERFLOW;		goto idata_err;	} 	if (!idata->buf_bytes) {		idata->buf = NULL;		return idata;	} 	idata->buf = memdup_user((void __user *)(unsigned long)				 idata->ic.data_ptr, idata->buf_bytes);	if (IS_ERR(idata->buf)) {		err = PTR_ERR(idata->buf);		goto idata_err;	} 	return idata; idata_err:	kfree(idata);out:	return ERR_PTR(err);} static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,				      struct mmc_blk_ioc_data *idata){	struct mmc_ioc_cmd *ic = &idata->ic; 	if (copy_to_user(&(ic_ptr->response), ic->response,			 sizeof(ic->response)))		return -EFAULT; 	if (!idata->ic.write_flag) {		if (copy_to_user((void __user *)(unsigned long)ic->data_ptr,				 idata->buf, idata->buf_bytes))			return -EFAULT;	} 	return 0;} static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,			       struct mmc_blk_ioc_data **idatas, int i){	struct mmc_command cmd = {}, sbc = {};	struct mmc_data data = {};	struct mmc_request mrq = {};	struct scatterlist sg;	bool r1b_resp;	unsigned int busy_timeout_ms;	int err;	unsigned int target_part;	struct mmc_blk_ioc_data *idata = idatas[i];	struct mmc_blk_ioc_data *prev_idata = NULL; 	if (!card || !md || !idata)		return -EINVAL; 	if (idata->flags & MMC_BLK_IOC_DROP)		return 0; 	if (idata->flags & MMC_BLK_IOC_SBC && i > 0)

Lines 1–500 of 3392.