162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014 Ezequiel Garcia
462306a36Sopenharmony_ci * Copyright (c) 2011 Free Electrons
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Driver parameter handling strongly based on drivers/mtd/ubi/build.c
762306a36Sopenharmony_ci *   Copyright (c) International Business Machines Corp., 2006
862306a36Sopenharmony_ci *   Copyright (c) Nokia Corporation, 2007
962306a36Sopenharmony_ci *   Authors: Artem Bityutskiy, Frank Haverkamp
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci * Read-only block devices on top of UBI volumes
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * A simple implementation to allow a block device to be layered on top of a
1662306a36Sopenharmony_ci * UBI volume. The implementation is provided by creating a static 1-to-1
1762306a36Sopenharmony_ci * mapping between the block device and the UBI volume.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * The addressed byte is obtained from the addressed block sector, which is
2062306a36Sopenharmony_ci * mapped linearly into the corresponding LEB:
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *   LEB number = addressed byte / LEB size
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * This feature is compiled in the UBI core, and adds a 'block' parameter
2562306a36Sopenharmony_ci * to allow early creation of block devices on top of UBI volumes. Runtime
2662306a36Sopenharmony_ci * block creation/removal for UBI volumes is provided through two UBI ioctls:
2762306a36Sopenharmony_ci * UBI_IOCVOLCRBLK and UBI_IOCVOLRMBLK.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <linux/module.h>
3162306a36Sopenharmony_ci#include <linux/init.h>
3262306a36Sopenharmony_ci#include <linux/err.h>
3362306a36Sopenharmony_ci#include <linux/kernel.h>
3462306a36Sopenharmony_ci#include <linux/list.h>
3562306a36Sopenharmony_ci#include <linux/mutex.h>
3662306a36Sopenharmony_ci#include <linux/slab.h>
3762306a36Sopenharmony_ci#include <linux/mtd/ubi.h>
3862306a36Sopenharmony_ci#include <linux/blkdev.h>
3962306a36Sopenharmony_ci#include <linux/blk-mq.h>
4062306a36Sopenharmony_ci#include <linux/hdreg.h>
4162306a36Sopenharmony_ci#include <linux/scatterlist.h>
4262306a36Sopenharmony_ci#include <linux/idr.h>
4362306a36Sopenharmony_ci#include <asm/div64.h>
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#include "ubi-media.h"
4662306a36Sopenharmony_ci#include "ubi.h"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Maximum number of supported devices */
4962306a36Sopenharmony_ci#define UBIBLOCK_MAX_DEVICES 32
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Maximum length of the 'block=' parameter */
5262306a36Sopenharmony_ci#define UBIBLOCK_PARAM_LEN 63
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* Maximum number of comma-separated items in the 'block=' parameter */
5562306a36Sopenharmony_ci#define UBIBLOCK_PARAM_COUNT 2
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct ubiblock_param {
5862306a36Sopenharmony_ci	int ubi_num;
5962306a36Sopenharmony_ci	int vol_id;
6062306a36Sopenharmony_ci	char name[UBIBLOCK_PARAM_LEN+1];
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct ubiblock_pdu {
6462306a36Sopenharmony_ci	struct ubi_sgl usgl;
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* Numbers of elements set in the @ubiblock_param array */
6862306a36Sopenharmony_cistatic int ubiblock_devs __initdata;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* MTD devices specification parameters */
7162306a36Sopenharmony_cistatic struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct ubiblock {
7462306a36Sopenharmony_ci	struct ubi_volume_desc *desc;
7562306a36Sopenharmony_ci	int ubi_num;
7662306a36Sopenharmony_ci	int vol_id;
7762306a36Sopenharmony_ci	int refcnt;
7862306a36Sopenharmony_ci	int leb_size;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	struct gendisk *gd;
8162306a36Sopenharmony_ci	struct request_queue *rq;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	struct mutex dev_mutex;
8462306a36Sopenharmony_ci	struct list_head list;
8562306a36Sopenharmony_ci	struct blk_mq_tag_set tag_set;
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* Linked list of all ubiblock instances */
8962306a36Sopenharmony_cistatic LIST_HEAD(ubiblock_devices);
9062306a36Sopenharmony_cistatic DEFINE_IDR(ubiblock_minor_idr);
9162306a36Sopenharmony_ci/* Protects ubiblock_devices and ubiblock_minor_idr */
9262306a36Sopenharmony_cistatic DEFINE_MUTEX(devices_mutex);
9362306a36Sopenharmony_cistatic int ubiblock_major;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int __init ubiblock_set_param(const char *val,
9662306a36Sopenharmony_ci				     const struct kernel_param *kp)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	int i, ret;
9962306a36Sopenharmony_ci	size_t len;
10062306a36Sopenharmony_ci	struct ubiblock_param *param;
10162306a36Sopenharmony_ci	char buf[UBIBLOCK_PARAM_LEN];
10262306a36Sopenharmony_ci	char *pbuf = &buf[0];
10362306a36Sopenharmony_ci	char *tokens[UBIBLOCK_PARAM_COUNT];
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (!val)
10662306a36Sopenharmony_ci		return -EINVAL;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	len = strnlen(val, UBIBLOCK_PARAM_LEN);
10962306a36Sopenharmony_ci	if (len == 0) {
11062306a36Sopenharmony_ci		pr_warn("UBI: block: empty 'block=' parameter - ignored\n");
11162306a36Sopenharmony_ci		return 0;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (len == UBIBLOCK_PARAM_LEN) {
11562306a36Sopenharmony_ci		pr_err("UBI: block: parameter \"%s\" is too long, max. is %d\n",
11662306a36Sopenharmony_ci		       val, UBIBLOCK_PARAM_LEN);
11762306a36Sopenharmony_ci		return -EINVAL;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	strcpy(buf, val);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* Get rid of the final newline */
12362306a36Sopenharmony_ci	if (buf[len - 1] == '\n')
12462306a36Sopenharmony_ci		buf[len - 1] = '\0';
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	for (i = 0; i < UBIBLOCK_PARAM_COUNT; i++)
12762306a36Sopenharmony_ci		tokens[i] = strsep(&pbuf, ",");
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	param = &ubiblock_param[ubiblock_devs];
13062306a36Sopenharmony_ci	if (tokens[1]) {
13162306a36Sopenharmony_ci		/* Two parameters: can be 'ubi, vol_id' or 'ubi, vol_name' */
13262306a36Sopenharmony_ci		ret = kstrtoint(tokens[0], 10, &param->ubi_num);
13362306a36Sopenharmony_ci		if (ret < 0)
13462306a36Sopenharmony_ci			return -EINVAL;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		/* Second param can be a number or a name */
13762306a36Sopenharmony_ci		ret = kstrtoint(tokens[1], 10, &param->vol_id);
13862306a36Sopenharmony_ci		if (ret < 0) {
13962306a36Sopenharmony_ci			param->vol_id = -1;
14062306a36Sopenharmony_ci			strcpy(param->name, tokens[1]);
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	} else {
14462306a36Sopenharmony_ci		/* One parameter: must be device path */
14562306a36Sopenharmony_ci		strcpy(param->name, tokens[0]);
14662306a36Sopenharmony_ci		param->ubi_num = -1;
14762306a36Sopenharmony_ci		param->vol_id = -1;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	ubiblock_devs++;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return 0;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic const struct kernel_param_ops ubiblock_param_ops = {
15662306a36Sopenharmony_ci	.set    = ubiblock_set_param,
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_cimodule_param_cb(block, &ubiblock_param_ops, NULL, 0);
15962306a36Sopenharmony_ciMODULE_PARM_DESC(block, "Attach block devices to UBI volumes. Parameter format: block=<path|dev,num|dev,name>.\n"
16062306a36Sopenharmony_ci			"Multiple \"block\" parameters may be specified.\n"
16162306a36Sopenharmony_ci			"UBI volumes may be specified by their number, name, or path to the device node.\n"
16262306a36Sopenharmony_ci			"Examples\n"
16362306a36Sopenharmony_ci			"Using the UBI volume path:\n"
16462306a36Sopenharmony_ci			"ubi.block=/dev/ubi0_0\n"
16562306a36Sopenharmony_ci			"Using the UBI device, and the volume name:\n"
16662306a36Sopenharmony_ci			"ubi.block=0,rootfs\n"
16762306a36Sopenharmony_ci			"Using both UBI device number and UBI volume number:\n"
16862306a36Sopenharmony_ci			"ubi.block=0,0\n");
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct ubiblock *dev;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	list_for_each_entry(dev, &ubiblock_devices, list)
17562306a36Sopenharmony_ci		if (dev->ubi_num == ubi_num && dev->vol_id == vol_id)
17662306a36Sopenharmony_ci			return dev;
17762306a36Sopenharmony_ci	return NULL;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic blk_status_t ubiblock_read(struct request *req)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
18362306a36Sopenharmony_ci	struct ubiblock *dev = req->q->queuedata;
18462306a36Sopenharmony_ci	u64 pos = blk_rq_pos(req) << 9;
18562306a36Sopenharmony_ci	int to_read = blk_rq_bytes(req);
18662306a36Sopenharmony_ci	int bytes_left = to_read;
18762306a36Sopenharmony_ci	/* Get LEB:offset address to read from */
18862306a36Sopenharmony_ci	int offset = do_div(pos, dev->leb_size);
18962306a36Sopenharmony_ci	int leb = pos;
19062306a36Sopenharmony_ci	struct req_iterator iter;
19162306a36Sopenharmony_ci	struct bio_vec bvec;
19262306a36Sopenharmony_ci	int ret;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	blk_mq_start_request(req);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/*
19762306a36Sopenharmony_ci	 * It is safe to ignore the return value of blk_rq_map_sg() because
19862306a36Sopenharmony_ci	 * the number of sg entries is limited to UBI_MAX_SG_COUNT
19962306a36Sopenharmony_ci	 * and ubi_read_sg() will check that limit.
20062306a36Sopenharmony_ci	 */
20162306a36Sopenharmony_ci	ubi_sgl_init(&pdu->usgl);
20262306a36Sopenharmony_ci	blk_rq_map_sg(req->q, req, pdu->usgl.sg);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	while (bytes_left) {
20562306a36Sopenharmony_ci		/*
20662306a36Sopenharmony_ci		 * We can only read one LEB at a time. Therefore if the read
20762306a36Sopenharmony_ci		 * length is larger than one LEB size, we split the operation.
20862306a36Sopenharmony_ci		 */
20962306a36Sopenharmony_ci		if (offset + to_read > dev->leb_size)
21062306a36Sopenharmony_ci			to_read = dev->leb_size - offset;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read);
21362306a36Sopenharmony_ci		if (ret < 0)
21462306a36Sopenharmony_ci			break;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		bytes_left -= to_read;
21762306a36Sopenharmony_ci		to_read = bytes_left;
21862306a36Sopenharmony_ci		leb += 1;
21962306a36Sopenharmony_ci		offset = 0;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	rq_for_each_segment(bvec, req, iter)
22362306a36Sopenharmony_ci		flush_dcache_page(bvec.bv_page);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	blk_mq_end_request(req, errno_to_blk_status(ret));
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return BLK_STS_OK;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int ubiblock_open(struct gendisk *disk, blk_mode_t mode)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct ubiblock *dev = disk->private_data;
23362306a36Sopenharmony_ci	int ret;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	mutex_lock(&dev->dev_mutex);
23662306a36Sopenharmony_ci	if (dev->refcnt > 0) {
23762306a36Sopenharmony_ci		/*
23862306a36Sopenharmony_ci		 * The volume is already open, just increase the reference
23962306a36Sopenharmony_ci		 * counter.
24062306a36Sopenharmony_ci		 */
24162306a36Sopenharmony_ci		goto out_done;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/*
24562306a36Sopenharmony_ci	 * We want users to be aware they should only mount us as read-only.
24662306a36Sopenharmony_ci	 * It's just a paranoid check, as write requests will get rejected
24762306a36Sopenharmony_ci	 * in any case.
24862306a36Sopenharmony_ci	 */
24962306a36Sopenharmony_ci	if (mode & BLK_OPEN_WRITE) {
25062306a36Sopenharmony_ci		ret = -EROFS;
25162306a36Sopenharmony_ci		goto out_unlock;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci	dev->desc = ubi_open_volume(dev->ubi_num, dev->vol_id, UBI_READONLY);
25462306a36Sopenharmony_ci	if (IS_ERR(dev->desc)) {
25562306a36Sopenharmony_ci		dev_err(disk_to_dev(dev->gd), "failed to open ubi volume %d_%d",
25662306a36Sopenharmony_ci			dev->ubi_num, dev->vol_id);
25762306a36Sopenharmony_ci		ret = PTR_ERR(dev->desc);
25862306a36Sopenharmony_ci		dev->desc = NULL;
25962306a36Sopenharmony_ci		goto out_unlock;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciout_done:
26362306a36Sopenharmony_ci	dev->refcnt++;
26462306a36Sopenharmony_ci	mutex_unlock(&dev->dev_mutex);
26562306a36Sopenharmony_ci	return 0;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ciout_unlock:
26862306a36Sopenharmony_ci	mutex_unlock(&dev->dev_mutex);
26962306a36Sopenharmony_ci	return ret;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void ubiblock_release(struct gendisk *gd)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct ubiblock *dev = gd->private_data;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	mutex_lock(&dev->dev_mutex);
27762306a36Sopenharmony_ci	dev->refcnt--;
27862306a36Sopenharmony_ci	if (dev->refcnt == 0) {
27962306a36Sopenharmony_ci		ubi_close_volume(dev->desc);
28062306a36Sopenharmony_ci		dev->desc = NULL;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci	mutex_unlock(&dev->dev_mutex);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic int ubiblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	/* Some tools might require this information */
28862306a36Sopenharmony_ci	geo->heads = 1;
28962306a36Sopenharmony_ci	geo->cylinders = 1;
29062306a36Sopenharmony_ci	geo->sectors = get_capacity(bdev->bd_disk);
29162306a36Sopenharmony_ci	geo->start = 0;
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic const struct block_device_operations ubiblock_ops = {
29662306a36Sopenharmony_ci	.owner = THIS_MODULE,
29762306a36Sopenharmony_ci	.open = ubiblock_open,
29862306a36Sopenharmony_ci	.release = ubiblock_release,
29962306a36Sopenharmony_ci	.getgeo	= ubiblock_getgeo,
30062306a36Sopenharmony_ci};
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic blk_status_t ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx,
30362306a36Sopenharmony_ci			     const struct blk_mq_queue_data *bd)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	switch (req_op(bd->rq)) {
30662306a36Sopenharmony_ci	case REQ_OP_READ:
30762306a36Sopenharmony_ci		return ubiblock_read(bd->rq);
30862306a36Sopenharmony_ci	default:
30962306a36Sopenharmony_ci		return BLK_STS_IOERR;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic int ubiblock_init_request(struct blk_mq_tag_set *set,
31462306a36Sopenharmony_ci		struct request *req, unsigned int hctx_idx,
31562306a36Sopenharmony_ci		unsigned int numa_node)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	sg_init_table(pdu->usgl.sg, UBI_MAX_SG_COUNT);
32062306a36Sopenharmony_ci	return 0;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic const struct blk_mq_ops ubiblock_mq_ops = {
32462306a36Sopenharmony_ci	.queue_rq       = ubiblock_queue_rq,
32562306a36Sopenharmony_ci	.init_request	= ubiblock_init_request,
32662306a36Sopenharmony_ci};
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int calc_disk_capacity(struct ubi_volume_info *vi, u64 *disk_capacity)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	u64 size = vi->used_bytes >> 9;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (vi->used_bytes % 512) {
33362306a36Sopenharmony_ci		if (vi->vol_type == UBI_DYNAMIC_VOLUME)
33462306a36Sopenharmony_ci			pr_warn("UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored!\n",
33562306a36Sopenharmony_ci				vi->used_bytes - (size << 9));
33662306a36Sopenharmony_ci		else
33762306a36Sopenharmony_ci			pr_info("UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored!\n",
33862306a36Sopenharmony_ci				vi->used_bytes - (size << 9));
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if ((sector_t)size != size)
34262306a36Sopenharmony_ci		return -EFBIG;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	*disk_capacity = size;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return 0;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ciint ubiblock_create(struct ubi_volume_info *vi)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct ubiblock *dev;
35262306a36Sopenharmony_ci	struct gendisk *gd;
35362306a36Sopenharmony_ci	u64 disk_capacity;
35462306a36Sopenharmony_ci	int ret;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	ret = calc_disk_capacity(vi, &disk_capacity);
35762306a36Sopenharmony_ci	if (ret) {
35862306a36Sopenharmony_ci		return ret;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* Check that the volume isn't already handled */
36262306a36Sopenharmony_ci	mutex_lock(&devices_mutex);
36362306a36Sopenharmony_ci	if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
36462306a36Sopenharmony_ci		ret = -EEXIST;
36562306a36Sopenharmony_ci		goto out_unlock;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
36962306a36Sopenharmony_ci	if (!dev) {
37062306a36Sopenharmony_ci		ret = -ENOMEM;
37162306a36Sopenharmony_ci		goto out_unlock;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	mutex_init(&dev->dev_mutex);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	dev->ubi_num = vi->ubi_num;
37762306a36Sopenharmony_ci	dev->vol_id = vi->vol_id;
37862306a36Sopenharmony_ci	dev->leb_size = vi->usable_leb_size;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	dev->tag_set.ops = &ubiblock_mq_ops;
38162306a36Sopenharmony_ci	dev->tag_set.queue_depth = 64;
38262306a36Sopenharmony_ci	dev->tag_set.numa_node = NUMA_NO_NODE;
38362306a36Sopenharmony_ci	dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
38462306a36Sopenharmony_ci	dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
38562306a36Sopenharmony_ci	dev->tag_set.driver_data = dev;
38662306a36Sopenharmony_ci	dev->tag_set.nr_hw_queues = 1;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	ret = blk_mq_alloc_tag_set(&dev->tag_set);
38962306a36Sopenharmony_ci	if (ret) {
39062306a36Sopenharmony_ci		dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
39162306a36Sopenharmony_ci		goto out_free_dev;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	/* Initialize the gendisk of this ubiblock device */
39662306a36Sopenharmony_ci	gd = blk_mq_alloc_disk(&dev->tag_set, dev);
39762306a36Sopenharmony_ci	if (IS_ERR(gd)) {
39862306a36Sopenharmony_ci		ret = PTR_ERR(gd);
39962306a36Sopenharmony_ci		goto out_free_tags;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	gd->fops = &ubiblock_ops;
40362306a36Sopenharmony_ci	gd->major = ubiblock_major;
40462306a36Sopenharmony_ci	gd->minors = 1;
40562306a36Sopenharmony_ci	gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
40662306a36Sopenharmony_ci	if (gd->first_minor < 0) {
40762306a36Sopenharmony_ci		dev_err(disk_to_dev(gd),
40862306a36Sopenharmony_ci			"block: dynamic minor allocation failed");
40962306a36Sopenharmony_ci		ret = -ENODEV;
41062306a36Sopenharmony_ci		goto out_cleanup_disk;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci	gd->flags |= GENHD_FL_NO_PART;
41362306a36Sopenharmony_ci	gd->private_data = dev;
41462306a36Sopenharmony_ci	sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
41562306a36Sopenharmony_ci	set_capacity(gd, disk_capacity);
41662306a36Sopenharmony_ci	dev->gd = gd;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	dev->rq = gd->queue;
41962306a36Sopenharmony_ci	blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	list_add_tail(&dev->list, &ubiblock_devices);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* Must be the last step: anyone can call file ops from now on */
42462306a36Sopenharmony_ci	ret = device_add_disk(vi->dev, dev->gd, NULL);
42562306a36Sopenharmony_ci	if (ret)
42662306a36Sopenharmony_ci		goto out_remove_minor;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
42962306a36Sopenharmony_ci		 dev->ubi_num, dev->vol_id, vi->name);
43062306a36Sopenharmony_ci	mutex_unlock(&devices_mutex);
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ciout_remove_minor:
43462306a36Sopenharmony_ci	list_del(&dev->list);
43562306a36Sopenharmony_ci	idr_remove(&ubiblock_minor_idr, gd->first_minor);
43662306a36Sopenharmony_ciout_cleanup_disk:
43762306a36Sopenharmony_ci	put_disk(dev->gd);
43862306a36Sopenharmony_ciout_free_tags:
43962306a36Sopenharmony_ci	blk_mq_free_tag_set(&dev->tag_set);
44062306a36Sopenharmony_ciout_free_dev:
44162306a36Sopenharmony_ci	kfree(dev);
44262306a36Sopenharmony_ciout_unlock:
44362306a36Sopenharmony_ci	mutex_unlock(&devices_mutex);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return ret;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic void ubiblock_cleanup(struct ubiblock *dev)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	/* Stop new requests to arrive */
45162306a36Sopenharmony_ci	del_gendisk(dev->gd);
45262306a36Sopenharmony_ci	/* Finally destroy the blk queue */
45362306a36Sopenharmony_ci	dev_info(disk_to_dev(dev->gd), "released");
45462306a36Sopenharmony_ci	put_disk(dev->gd);
45562306a36Sopenharmony_ci	blk_mq_free_tag_set(&dev->tag_set);
45662306a36Sopenharmony_ci	idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ciint ubiblock_remove(struct ubi_volume_info *vi)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct ubiblock *dev;
46262306a36Sopenharmony_ci	int ret;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	mutex_lock(&devices_mutex);
46562306a36Sopenharmony_ci	dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
46662306a36Sopenharmony_ci	if (!dev) {
46762306a36Sopenharmony_ci		ret = -ENODEV;
46862306a36Sopenharmony_ci		goto out_unlock;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Found a device, let's lock it so we can check if it's busy */
47262306a36Sopenharmony_ci	mutex_lock(&dev->dev_mutex);
47362306a36Sopenharmony_ci	if (dev->refcnt > 0) {
47462306a36Sopenharmony_ci		ret = -EBUSY;
47562306a36Sopenharmony_ci		goto out_unlock_dev;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	/* Remove from device list */
47962306a36Sopenharmony_ci	list_del(&dev->list);
48062306a36Sopenharmony_ci	ubiblock_cleanup(dev);
48162306a36Sopenharmony_ci	mutex_unlock(&dev->dev_mutex);
48262306a36Sopenharmony_ci	mutex_unlock(&devices_mutex);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	kfree(dev);
48562306a36Sopenharmony_ci	return 0;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ciout_unlock_dev:
48862306a36Sopenharmony_ci	mutex_unlock(&dev->dev_mutex);
48962306a36Sopenharmony_ciout_unlock:
49062306a36Sopenharmony_ci	mutex_unlock(&devices_mutex);
49162306a36Sopenharmony_ci	return ret;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic int ubiblock_resize(struct ubi_volume_info *vi)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct ubiblock *dev;
49762306a36Sopenharmony_ci	u64 disk_capacity;
49862306a36Sopenharmony_ci	int ret;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/*
50162306a36Sopenharmony_ci	 * Need to lock the device list until we stop using the device,
50262306a36Sopenharmony_ci	 * otherwise the device struct might get released in
50362306a36Sopenharmony_ci	 * 'ubiblock_remove()'.
50462306a36Sopenharmony_ci	 */
50562306a36Sopenharmony_ci	mutex_lock(&devices_mutex);
50662306a36Sopenharmony_ci	dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
50762306a36Sopenharmony_ci	if (!dev) {
50862306a36Sopenharmony_ci		mutex_unlock(&devices_mutex);
50962306a36Sopenharmony_ci		return -ENODEV;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	ret = calc_disk_capacity(vi, &disk_capacity);
51362306a36Sopenharmony_ci	if (ret) {
51462306a36Sopenharmony_ci		mutex_unlock(&devices_mutex);
51562306a36Sopenharmony_ci		if (ret == -EFBIG) {
51662306a36Sopenharmony_ci			dev_warn(disk_to_dev(dev->gd),
51762306a36Sopenharmony_ci				 "the volume is too big (%d LEBs), cannot resize",
51862306a36Sopenharmony_ci				 vi->size);
51962306a36Sopenharmony_ci		}
52062306a36Sopenharmony_ci		return ret;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	mutex_lock(&dev->dev_mutex);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (get_capacity(dev->gd) != disk_capacity) {
52662306a36Sopenharmony_ci		set_capacity(dev->gd, disk_capacity);
52762306a36Sopenharmony_ci		dev_info(disk_to_dev(dev->gd), "resized to %lld bytes",
52862306a36Sopenharmony_ci			 vi->used_bytes);
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci	mutex_unlock(&dev->dev_mutex);
53162306a36Sopenharmony_ci	mutex_unlock(&devices_mutex);
53262306a36Sopenharmony_ci	return 0;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic int ubiblock_notify(struct notifier_block *nb,
53662306a36Sopenharmony_ci			 unsigned long notification_type, void *ns_ptr)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct ubi_notification *nt = ns_ptr;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	switch (notification_type) {
54162306a36Sopenharmony_ci	case UBI_VOLUME_ADDED:
54262306a36Sopenharmony_ci		/*
54362306a36Sopenharmony_ci		 * We want to enforce explicit block device creation for
54462306a36Sopenharmony_ci		 * volumes, so when a volume is added we do nothing.
54562306a36Sopenharmony_ci		 */
54662306a36Sopenharmony_ci		break;
54762306a36Sopenharmony_ci	case UBI_VOLUME_REMOVED:
54862306a36Sopenharmony_ci		ubiblock_remove(&nt->vi);
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci	case UBI_VOLUME_RESIZED:
55162306a36Sopenharmony_ci		ubiblock_resize(&nt->vi);
55262306a36Sopenharmony_ci		break;
55362306a36Sopenharmony_ci	case UBI_VOLUME_UPDATED:
55462306a36Sopenharmony_ci		/*
55562306a36Sopenharmony_ci		 * If the volume is static, a content update might mean the
55662306a36Sopenharmony_ci		 * size (i.e. used_bytes) was also changed.
55762306a36Sopenharmony_ci		 */
55862306a36Sopenharmony_ci		if (nt->vi.vol_type == UBI_STATIC_VOLUME)
55962306a36Sopenharmony_ci			ubiblock_resize(&nt->vi);
56062306a36Sopenharmony_ci		break;
56162306a36Sopenharmony_ci	default:
56262306a36Sopenharmony_ci		break;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci	return NOTIFY_OK;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic struct notifier_block ubiblock_notifier = {
56862306a36Sopenharmony_ci	.notifier_call = ubiblock_notify,
56962306a36Sopenharmony_ci};
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistatic struct ubi_volume_desc * __init
57262306a36Sopenharmony_ciopen_volume_desc(const char *name, int ubi_num, int vol_id)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	if (ubi_num == -1)
57562306a36Sopenharmony_ci		/* No ubi num, name must be a vol device path */
57662306a36Sopenharmony_ci		return ubi_open_volume_path(name, UBI_READONLY);
57762306a36Sopenharmony_ci	else if (vol_id == -1)
57862306a36Sopenharmony_ci		/* No vol_id, must be vol_name */
57962306a36Sopenharmony_ci		return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
58062306a36Sopenharmony_ci	else
58162306a36Sopenharmony_ci		return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic void __init ubiblock_create_from_param(void)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	int i, ret = 0;
58762306a36Sopenharmony_ci	struct ubiblock_param *p;
58862306a36Sopenharmony_ci	struct ubi_volume_desc *desc;
58962306a36Sopenharmony_ci	struct ubi_volume_info vi;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/*
59262306a36Sopenharmony_ci	 * If there is an error creating one of the ubiblocks, continue on to
59362306a36Sopenharmony_ci	 * create the following ubiblocks. This helps in a circumstance where
59462306a36Sopenharmony_ci	 * the kernel command-line specifies multiple block devices and some
59562306a36Sopenharmony_ci	 * may be broken, but we still want the working ones to come up.
59662306a36Sopenharmony_ci	 */
59762306a36Sopenharmony_ci	for (i = 0; i < ubiblock_devs; i++) {
59862306a36Sopenharmony_ci		p = &ubiblock_param[i];
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
60162306a36Sopenharmony_ci		if (IS_ERR(desc)) {
60262306a36Sopenharmony_ci			pr_err(
60362306a36Sopenharmony_ci			       "UBI: block: can't open volume on ubi%d_%d, err=%ld\n",
60462306a36Sopenharmony_ci			       p->ubi_num, p->vol_id, PTR_ERR(desc));
60562306a36Sopenharmony_ci			continue;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		ubi_get_volume_info(desc, &vi);
60962306a36Sopenharmony_ci		ubi_close_volume(desc);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		ret = ubiblock_create(&vi);
61262306a36Sopenharmony_ci		if (ret) {
61362306a36Sopenharmony_ci			pr_err(
61462306a36Sopenharmony_ci			       "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
61562306a36Sopenharmony_ci			       vi.name, p->ubi_num, p->vol_id, ret);
61662306a36Sopenharmony_ci			continue;
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic void ubiblock_remove_all(void)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct ubiblock *next;
62462306a36Sopenharmony_ci	struct ubiblock *dev;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	mutex_lock(&devices_mutex);
62762306a36Sopenharmony_ci	list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
62862306a36Sopenharmony_ci		/* The module is being forcefully removed */
62962306a36Sopenharmony_ci		WARN_ON(dev->desc);
63062306a36Sopenharmony_ci		/* Remove from device list */
63162306a36Sopenharmony_ci		list_del(&dev->list);
63262306a36Sopenharmony_ci		ubiblock_cleanup(dev);
63362306a36Sopenharmony_ci		kfree(dev);
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci	mutex_unlock(&devices_mutex);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ciint __init ubiblock_init(void)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	int ret;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	ubiblock_major = register_blkdev(0, "ubiblock");
64362306a36Sopenharmony_ci	if (ubiblock_major < 0)
64462306a36Sopenharmony_ci		return ubiblock_major;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/*
64762306a36Sopenharmony_ci	 * Attach block devices from 'block=' module param.
64862306a36Sopenharmony_ci	 * Even if one block device in the param list fails to come up,
64962306a36Sopenharmony_ci	 * still allow the module to load and leave any others up.
65062306a36Sopenharmony_ci	 */
65162306a36Sopenharmony_ci	ubiblock_create_from_param();
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/*
65462306a36Sopenharmony_ci	 * Block devices are only created upon user requests, so we ignore
65562306a36Sopenharmony_ci	 * existing volumes.
65662306a36Sopenharmony_ci	 */
65762306a36Sopenharmony_ci	ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
65862306a36Sopenharmony_ci	if (ret)
65962306a36Sopenharmony_ci		goto err_unreg;
66062306a36Sopenharmony_ci	return 0;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cierr_unreg:
66362306a36Sopenharmony_ci	unregister_blkdev(ubiblock_major, "ubiblock");
66462306a36Sopenharmony_ci	ubiblock_remove_all();
66562306a36Sopenharmony_ci	return ret;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_civoid __exit ubiblock_exit(void)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	ubi_unregister_volume_notifier(&ubiblock_notifier);
67162306a36Sopenharmony_ci	ubiblock_remove_all();
67262306a36Sopenharmony_ci	unregister_blkdev(ubiblock_major, "ubiblock");
67362306a36Sopenharmony_ci}
674