162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __BLK_NULL_BLK_H
362306a36Sopenharmony_ci#define __BLK_NULL_BLK_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#undef pr_fmt
662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/blkdev.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/blk-mq.h>
1162306a36Sopenharmony_ci#include <linux/hrtimer.h>
1262306a36Sopenharmony_ci#include <linux/configfs.h>
1362306a36Sopenharmony_ci#include <linux/badblocks.h>
1462306a36Sopenharmony_ci#include <linux/fault-inject.h>
1562306a36Sopenharmony_ci#include <linux/spinlock.h>
1662306a36Sopenharmony_ci#include <linux/mutex.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct nullb_cmd {
1962306a36Sopenharmony_ci	union {
2062306a36Sopenharmony_ci		struct request *rq;
2162306a36Sopenharmony_ci		struct bio *bio;
2262306a36Sopenharmony_ci	};
2362306a36Sopenharmony_ci	unsigned int tag;
2462306a36Sopenharmony_ci	blk_status_t error;
2562306a36Sopenharmony_ci	bool fake_timeout;
2662306a36Sopenharmony_ci	struct nullb_queue *nq;
2762306a36Sopenharmony_ci	struct hrtimer timer;
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct nullb_queue {
3162306a36Sopenharmony_ci	unsigned long *tag_map;
3262306a36Sopenharmony_ci	wait_queue_head_t wait;
3362306a36Sopenharmony_ci	unsigned int queue_depth;
3462306a36Sopenharmony_ci	struct nullb_device *dev;
3562306a36Sopenharmony_ci	unsigned int requeue_selection;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	struct list_head poll_list;
3862306a36Sopenharmony_ci	spinlock_t poll_lock;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	struct nullb_cmd *cmds;
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct nullb_zone {
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * Zone lock to prevent concurrent modification of a zone write
4662306a36Sopenharmony_ci	 * pointer position and condition: with memory backing, a write
4762306a36Sopenharmony_ci	 * command execution may sleep on memory allocation. For this case,
4862306a36Sopenharmony_ci	 * use mutex as the zone lock. Otherwise, use the spinlock for
4962306a36Sopenharmony_ci	 * locking the zone.
5062306a36Sopenharmony_ci	 */
5162306a36Sopenharmony_ci	union {
5262306a36Sopenharmony_ci		spinlock_t spinlock;
5362306a36Sopenharmony_ci		struct mutex mutex;
5462306a36Sopenharmony_ci	};
5562306a36Sopenharmony_ci	enum blk_zone_type type;
5662306a36Sopenharmony_ci	enum blk_zone_cond cond;
5762306a36Sopenharmony_ci	sector_t start;
5862306a36Sopenharmony_ci	sector_t wp;
5962306a36Sopenharmony_ci	unsigned int len;
6062306a36Sopenharmony_ci	unsigned int capacity;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/* Queue modes */
6462306a36Sopenharmony_cienum {
6562306a36Sopenharmony_ci	NULL_Q_BIO	= 0,
6662306a36Sopenharmony_ci	NULL_Q_RQ	= 1,
6762306a36Sopenharmony_ci	NULL_Q_MQ	= 2,
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistruct nullb_device {
7162306a36Sopenharmony_ci	struct nullb *nullb;
7262306a36Sopenharmony_ci	struct config_group group;
7362306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
7462306a36Sopenharmony_ci	struct fault_config timeout_config;
7562306a36Sopenharmony_ci	struct fault_config requeue_config;
7662306a36Sopenharmony_ci	struct fault_config init_hctx_fault_config;
7762306a36Sopenharmony_ci#endif
7862306a36Sopenharmony_ci	struct radix_tree_root data; /* data stored in the disk */
7962306a36Sopenharmony_ci	struct radix_tree_root cache; /* disk cache data */
8062306a36Sopenharmony_ci	unsigned long flags; /* device flags */
8162306a36Sopenharmony_ci	unsigned int curr_cache;
8262306a36Sopenharmony_ci	struct badblocks badblocks;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	unsigned int nr_zones;
8562306a36Sopenharmony_ci	unsigned int nr_zones_imp_open;
8662306a36Sopenharmony_ci	unsigned int nr_zones_exp_open;
8762306a36Sopenharmony_ci	unsigned int nr_zones_closed;
8862306a36Sopenharmony_ci	unsigned int imp_close_zone_no;
8962306a36Sopenharmony_ci	struct nullb_zone *zones;
9062306a36Sopenharmony_ci	sector_t zone_size_sects;
9162306a36Sopenharmony_ci	bool need_zone_res_mgmt;
9262306a36Sopenharmony_ci	spinlock_t zone_res_lock;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	unsigned long size; /* device size in MB */
9562306a36Sopenharmony_ci	unsigned long completion_nsec; /* time in ns to complete a request */
9662306a36Sopenharmony_ci	unsigned long cache_size; /* disk cache size in MB */
9762306a36Sopenharmony_ci	unsigned long zone_size; /* zone size in MB if device is zoned */
9862306a36Sopenharmony_ci	unsigned long zone_capacity; /* zone capacity in MB if device is zoned */
9962306a36Sopenharmony_ci	unsigned int zone_nr_conv; /* number of conventional zones */
10062306a36Sopenharmony_ci	unsigned int zone_max_open; /* max number of open zones */
10162306a36Sopenharmony_ci	unsigned int zone_max_active; /* max number of active zones */
10262306a36Sopenharmony_ci	unsigned int submit_queues; /* number of submission queues */
10362306a36Sopenharmony_ci	unsigned int prev_submit_queues; /* number of submission queues before change */
10462306a36Sopenharmony_ci	unsigned int poll_queues; /* number of IOPOLL submission queues */
10562306a36Sopenharmony_ci	unsigned int prev_poll_queues; /* number of IOPOLL submission queues before change */
10662306a36Sopenharmony_ci	unsigned int home_node; /* home node for the device */
10762306a36Sopenharmony_ci	unsigned int queue_mode; /* block interface */
10862306a36Sopenharmony_ci	unsigned int blocksize; /* block size */
10962306a36Sopenharmony_ci	unsigned int max_sectors; /* Max sectors per command */
11062306a36Sopenharmony_ci	unsigned int irqmode; /* IRQ completion handler */
11162306a36Sopenharmony_ci	unsigned int hw_queue_depth; /* queue depth */
11262306a36Sopenharmony_ci	unsigned int index; /* index of the disk, only valid with a disk */
11362306a36Sopenharmony_ci	unsigned int mbps; /* Bandwidth throttle cap (in MB/s) */
11462306a36Sopenharmony_ci	bool blocking; /* blocking blk-mq device */
11562306a36Sopenharmony_ci	bool use_per_node_hctx; /* use per-node allocation for hardware context */
11662306a36Sopenharmony_ci	bool power; /* power on/off the device */
11762306a36Sopenharmony_ci	bool memory_backed; /* if data is stored in memory */
11862306a36Sopenharmony_ci	bool discard; /* if support discard */
11962306a36Sopenharmony_ci	bool zoned; /* if device is zoned */
12062306a36Sopenharmony_ci	bool virt_boundary; /* virtual boundary on/off for the device */
12162306a36Sopenharmony_ci	bool no_sched; /* no IO scheduler for the device */
12262306a36Sopenharmony_ci	bool shared_tag_bitmap; /* use hostwide shared tags */
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistruct nullb {
12662306a36Sopenharmony_ci	struct nullb_device *dev;
12762306a36Sopenharmony_ci	struct list_head list;
12862306a36Sopenharmony_ci	unsigned int index;
12962306a36Sopenharmony_ci	struct request_queue *q;
13062306a36Sopenharmony_ci	struct gendisk *disk;
13162306a36Sopenharmony_ci	struct blk_mq_tag_set *tag_set;
13262306a36Sopenharmony_ci	struct blk_mq_tag_set __tag_set;
13362306a36Sopenharmony_ci	unsigned int queue_depth;
13462306a36Sopenharmony_ci	atomic_long_t cur_bytes;
13562306a36Sopenharmony_ci	struct hrtimer bw_timer;
13662306a36Sopenharmony_ci	unsigned long cache_flush_pos;
13762306a36Sopenharmony_ci	spinlock_t lock;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	struct nullb_queue *queues;
14062306a36Sopenharmony_ci	unsigned int nr_queues;
14162306a36Sopenharmony_ci	char disk_name[DISK_NAME_LEN];
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ciblk_status_t null_handle_discard(struct nullb_device *dev, sector_t sector,
14562306a36Sopenharmony_ci				 sector_t nr_sectors);
14662306a36Sopenharmony_ciblk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
14762306a36Sopenharmony_ci			      sector_t sector, unsigned int nr_sectors);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED
15062306a36Sopenharmony_ciint null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q);
15162306a36Sopenharmony_ciint null_register_zoned_dev(struct nullb *nullb);
15262306a36Sopenharmony_civoid null_free_zoned_dev(struct nullb_device *dev);
15362306a36Sopenharmony_ciint null_report_zones(struct gendisk *disk, sector_t sector,
15462306a36Sopenharmony_ci		      unsigned int nr_zones, report_zones_cb cb, void *data);
15562306a36Sopenharmony_ciblk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
15662306a36Sopenharmony_ci				    sector_t sector, sector_t nr_sectors);
15762306a36Sopenharmony_cisize_t null_zone_valid_read_len(struct nullb *nullb,
15862306a36Sopenharmony_ci				sector_t sector, unsigned int len);
15962306a36Sopenharmony_cissize_t zone_cond_store(struct nullb_device *dev, const char *page,
16062306a36Sopenharmony_ci			size_t count, enum blk_zone_cond cond);
16162306a36Sopenharmony_ci#else
16262306a36Sopenharmony_cistatic inline int null_init_zoned_dev(struct nullb_device *dev,
16362306a36Sopenharmony_ci				      struct request_queue *q)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	pr_err("CONFIG_BLK_DEV_ZONED not enabled\n");
16662306a36Sopenharmony_ci	return -EINVAL;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_cistatic inline int null_register_zoned_dev(struct nullb *nullb)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	return -ENODEV;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_cistatic inline void null_free_zoned_dev(struct nullb_device *dev) {}
17362306a36Sopenharmony_cistatic inline blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd,
17462306a36Sopenharmony_ci			enum req_op op, sector_t sector, sector_t nr_sectors)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	return BLK_STS_NOTSUPP;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_cistatic inline size_t null_zone_valid_read_len(struct nullb *nullb,
17962306a36Sopenharmony_ci					      sector_t sector,
18062306a36Sopenharmony_ci					      unsigned int len)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	return len;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_cistatic inline ssize_t zone_cond_store(struct nullb_device *dev,
18562306a36Sopenharmony_ci				      const char *page, size_t count,
18662306a36Sopenharmony_ci				      enum blk_zone_cond cond)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	return -EOPNOTSUPP;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci#define null_report_zones	NULL
19162306a36Sopenharmony_ci#endif /* CONFIG_BLK_DEV_ZONED */
19262306a36Sopenharmony_ci#endif /* __NULL_BLK_H */
193