// 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. Load more
// 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 int mmc_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)