162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * NVMe I/O command implementation.
462306a36Sopenharmony_ci * Copyright (c) 2015-2016 HGST, a Western Digital Company.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
762306a36Sopenharmony_ci#include <linux/blkdev.h>
862306a36Sopenharmony_ci#include <linux/blk-integrity.h>
962306a36Sopenharmony_ci#include <linux/memremap.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include "nvmet.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_civoid nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	/* Logical blocks per physical block, 0's based. */
1662306a36Sopenharmony_ci	const __le16 lpp0b = to0based(bdev_physical_block_size(bdev) /
1762306a36Sopenharmony_ci				      bdev_logical_block_size(bdev));
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	/*
2062306a36Sopenharmony_ci	 * For NVMe 1.2 and later, bit 1 indicates that the fields NAWUN,
2162306a36Sopenharmony_ci	 * NAWUPF, and NACWU are defined for this namespace and should be
2262306a36Sopenharmony_ci	 * used by the host for this namespace instead of the AWUN, AWUPF,
2362306a36Sopenharmony_ci	 * and ACWU fields in the Identify Controller data structure. If
2462306a36Sopenharmony_ci	 * any of these fields are zero that means that the corresponding
2562306a36Sopenharmony_ci	 * field from the identify controller data structure should be used.
2662306a36Sopenharmony_ci	 */
2762306a36Sopenharmony_ci	id->nsfeat |= 1 << 1;
2862306a36Sopenharmony_ci	id->nawun = lpp0b;
2962306a36Sopenharmony_ci	id->nawupf = lpp0b;
3062306a36Sopenharmony_ci	id->nacwu = lpp0b;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	/*
3362306a36Sopenharmony_ci	 * Bit 4 indicates that the fields NPWG, NPWA, NPDG, NPDA, and
3462306a36Sopenharmony_ci	 * NOWS are defined for this namespace and should be used by
3562306a36Sopenharmony_ci	 * the host for I/O optimization.
3662306a36Sopenharmony_ci	 */
3762306a36Sopenharmony_ci	id->nsfeat |= 1 << 4;
3862306a36Sopenharmony_ci	/* NPWG = Namespace Preferred Write Granularity. 0's based */
3962306a36Sopenharmony_ci	id->npwg = lpp0b;
4062306a36Sopenharmony_ci	/* NPWA = Namespace Preferred Write Alignment. 0's based */
4162306a36Sopenharmony_ci	id->npwa = id->npwg;
4262306a36Sopenharmony_ci	/* NPDG = Namespace Preferred Deallocate Granularity. 0's based */
4362306a36Sopenharmony_ci	id->npdg = to0based(bdev_discard_granularity(bdev) /
4462306a36Sopenharmony_ci			    bdev_logical_block_size(bdev));
4562306a36Sopenharmony_ci	/* NPDG = Namespace Preferred Deallocate Alignment */
4662306a36Sopenharmony_ci	id->npda = id->npdg;
4762306a36Sopenharmony_ci	/* NOWS = Namespace Optimal Write Size */
4862306a36Sopenharmony_ci	id->nows = to0based(bdev_io_opt(bdev) / bdev_logical_block_size(bdev));
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_civoid nvmet_bdev_ns_disable(struct nvmet_ns *ns)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	if (ns->bdev) {
5462306a36Sopenharmony_ci		blkdev_put(ns->bdev, NULL);
5562306a36Sopenharmony_ci		ns->bdev = NULL;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void nvmet_bdev_ns_enable_integrity(struct nvmet_ns *ns)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct blk_integrity *bi = bdev_get_integrity(ns->bdev);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (bi) {
6462306a36Sopenharmony_ci		ns->metadata_size = bi->tuple_size;
6562306a36Sopenharmony_ci		if (bi->profile == &t10_pi_type1_crc)
6662306a36Sopenharmony_ci			ns->pi_type = NVME_NS_DPS_PI_TYPE1;
6762306a36Sopenharmony_ci		else if (bi->profile == &t10_pi_type3_crc)
6862306a36Sopenharmony_ci			ns->pi_type = NVME_NS_DPS_PI_TYPE3;
6962306a36Sopenharmony_ci		else
7062306a36Sopenharmony_ci			/* Unsupported metadata type */
7162306a36Sopenharmony_ci			ns->metadata_size = 0;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciint nvmet_bdev_ns_enable(struct nvmet_ns *ns)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	int ret;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/*
8062306a36Sopenharmony_ci	 * When buffered_io namespace attribute is enabled that means user want
8162306a36Sopenharmony_ci	 * this block device to be used as a file, so block device can take
8262306a36Sopenharmony_ci	 * an advantage of cache.
8362306a36Sopenharmony_ci	 */
8462306a36Sopenharmony_ci	if (ns->buffered_io)
8562306a36Sopenharmony_ci		return -ENOTBLK;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	ns->bdev = blkdev_get_by_path(ns->device_path,
8862306a36Sopenharmony_ci			BLK_OPEN_READ | BLK_OPEN_WRITE, NULL, NULL);
8962306a36Sopenharmony_ci	if (IS_ERR(ns->bdev)) {
9062306a36Sopenharmony_ci		ret = PTR_ERR(ns->bdev);
9162306a36Sopenharmony_ci		if (ret != -ENOTBLK) {
9262306a36Sopenharmony_ci			pr_err("failed to open block device %s: (%ld)\n",
9362306a36Sopenharmony_ci					ns->device_path, PTR_ERR(ns->bdev));
9462306a36Sopenharmony_ci		}
9562306a36Sopenharmony_ci		ns->bdev = NULL;
9662306a36Sopenharmony_ci		return ret;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci	ns->size = bdev_nr_bytes(ns->bdev);
9962306a36Sopenharmony_ci	ns->blksize_shift = blksize_bits(bdev_logical_block_size(ns->bdev));
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	ns->pi_type = 0;
10262306a36Sopenharmony_ci	ns->metadata_size = 0;
10362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY_T10))
10462306a36Sopenharmony_ci		nvmet_bdev_ns_enable_integrity(ns);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (bdev_is_zoned(ns->bdev)) {
10762306a36Sopenharmony_ci		if (!nvmet_bdev_zns_enable(ns)) {
10862306a36Sopenharmony_ci			nvmet_bdev_ns_disable(ns);
10962306a36Sopenharmony_ci			return -EINVAL;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci		ns->csi = NVME_CSI_ZNS;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return 0;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_civoid nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	ns->size = bdev_nr_bytes(ns->bdev);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ciu16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	u16 status = NVME_SC_SUCCESS;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (likely(blk_sts == BLK_STS_OK))
12762306a36Sopenharmony_ci		return status;
12862306a36Sopenharmony_ci	/*
12962306a36Sopenharmony_ci	 * Right now there exists M : 1 mapping between block layer error
13062306a36Sopenharmony_ci	 * to the NVMe status code (see nvme_error_status()). For consistency,
13162306a36Sopenharmony_ci	 * when we reverse map we use most appropriate NVMe Status code from
13262306a36Sopenharmony_ci	 * the group of the NVMe staus codes used in the nvme_error_status().
13362306a36Sopenharmony_ci	 */
13462306a36Sopenharmony_ci	switch (blk_sts) {
13562306a36Sopenharmony_ci	case BLK_STS_NOSPC:
13662306a36Sopenharmony_ci		status = NVME_SC_CAP_EXCEEDED | NVME_SC_DNR;
13762306a36Sopenharmony_ci		req->error_loc = offsetof(struct nvme_rw_command, length);
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci	case BLK_STS_TARGET:
14062306a36Sopenharmony_ci		status = NVME_SC_LBA_RANGE | NVME_SC_DNR;
14162306a36Sopenharmony_ci		req->error_loc = offsetof(struct nvme_rw_command, slba);
14262306a36Sopenharmony_ci		break;
14362306a36Sopenharmony_ci	case BLK_STS_NOTSUPP:
14462306a36Sopenharmony_ci		req->error_loc = offsetof(struct nvme_common_command, opcode);
14562306a36Sopenharmony_ci		switch (req->cmd->common.opcode) {
14662306a36Sopenharmony_ci		case nvme_cmd_dsm:
14762306a36Sopenharmony_ci		case nvme_cmd_write_zeroes:
14862306a36Sopenharmony_ci			status = NVME_SC_ONCS_NOT_SUPPORTED | NVME_SC_DNR;
14962306a36Sopenharmony_ci			break;
15062306a36Sopenharmony_ci		default:
15162306a36Sopenharmony_ci			status = NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci		break;
15462306a36Sopenharmony_ci	case BLK_STS_MEDIUM:
15562306a36Sopenharmony_ci		status = NVME_SC_ACCESS_DENIED;
15662306a36Sopenharmony_ci		req->error_loc = offsetof(struct nvme_rw_command, nsid);
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case BLK_STS_IOERR:
15962306a36Sopenharmony_ci	default:
16062306a36Sopenharmony_ci		status = NVME_SC_INTERNAL | NVME_SC_DNR;
16162306a36Sopenharmony_ci		req->error_loc = offsetof(struct nvme_common_command, opcode);
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	switch (req->cmd->common.opcode) {
16562306a36Sopenharmony_ci	case nvme_cmd_read:
16662306a36Sopenharmony_ci	case nvme_cmd_write:
16762306a36Sopenharmony_ci		req->error_slba = le64_to_cpu(req->cmd->rw.slba);
16862306a36Sopenharmony_ci		break;
16962306a36Sopenharmony_ci	case nvme_cmd_write_zeroes:
17062306a36Sopenharmony_ci		req->error_slba =
17162306a36Sopenharmony_ci			le64_to_cpu(req->cmd->write_zeroes.slba);
17262306a36Sopenharmony_ci		break;
17362306a36Sopenharmony_ci	default:
17462306a36Sopenharmony_ci		req->error_slba = 0;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	return status;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic void nvmet_bio_done(struct bio *bio)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct nvmet_req *req = bio->bi_private;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	nvmet_req_complete(req, blk_to_nvme_status(req, bio->bi_status));
18462306a36Sopenharmony_ci	nvmet_req_bio_put(req, bio);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_INTEGRITY
18862306a36Sopenharmony_cistatic int nvmet_bdev_alloc_bip(struct nvmet_req *req, struct bio *bio,
18962306a36Sopenharmony_ci				struct sg_mapping_iter *miter)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct blk_integrity *bi;
19262306a36Sopenharmony_ci	struct bio_integrity_payload *bip;
19362306a36Sopenharmony_ci	int rc;
19462306a36Sopenharmony_ci	size_t resid, len;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	bi = bdev_get_integrity(req->ns->bdev);
19762306a36Sopenharmony_ci	if (unlikely(!bi)) {
19862306a36Sopenharmony_ci		pr_err("Unable to locate bio_integrity\n");
19962306a36Sopenharmony_ci		return -ENODEV;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	bip = bio_integrity_alloc(bio, GFP_NOIO,
20362306a36Sopenharmony_ci					bio_max_segs(req->metadata_sg_cnt));
20462306a36Sopenharmony_ci	if (IS_ERR(bip)) {
20562306a36Sopenharmony_ci		pr_err("Unable to allocate bio_integrity_payload\n");
20662306a36Sopenharmony_ci		return PTR_ERR(bip);
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* virtual start sector must be in integrity interval units */
21062306a36Sopenharmony_ci	bip_set_seed(bip, bio->bi_iter.bi_sector >>
21162306a36Sopenharmony_ci		     (bi->interval_exp - SECTOR_SHIFT));
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	resid = bio_integrity_bytes(bi, bio_sectors(bio));
21462306a36Sopenharmony_ci	while (resid > 0 && sg_miter_next(miter)) {
21562306a36Sopenharmony_ci		len = min_t(size_t, miter->length, resid);
21662306a36Sopenharmony_ci		rc = bio_integrity_add_page(bio, miter->page, len,
21762306a36Sopenharmony_ci					    offset_in_page(miter->addr));
21862306a36Sopenharmony_ci		if (unlikely(rc != len)) {
21962306a36Sopenharmony_ci			pr_err("bio_integrity_add_page() failed; %d\n", rc);
22062306a36Sopenharmony_ci			sg_miter_stop(miter);
22162306a36Sopenharmony_ci			return -ENOMEM;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		resid -= len;
22562306a36Sopenharmony_ci		if (len < miter->length)
22662306a36Sopenharmony_ci			miter->consumed -= miter->length - len;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci	sg_miter_stop(miter);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return 0;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci#else
23362306a36Sopenharmony_cistatic int nvmet_bdev_alloc_bip(struct nvmet_req *req, struct bio *bio,
23462306a36Sopenharmony_ci				struct sg_mapping_iter *miter)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	return -EINVAL;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci#endif /* CONFIG_BLK_DEV_INTEGRITY */
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic void nvmet_bdev_execute_rw(struct nvmet_req *req)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	unsigned int sg_cnt = req->sg_cnt;
24362306a36Sopenharmony_ci	struct bio *bio;
24462306a36Sopenharmony_ci	struct scatterlist *sg;
24562306a36Sopenharmony_ci	struct blk_plug plug;
24662306a36Sopenharmony_ci	sector_t sector;
24762306a36Sopenharmony_ci	blk_opf_t opf;
24862306a36Sopenharmony_ci	int i, rc;
24962306a36Sopenharmony_ci	struct sg_mapping_iter prot_miter;
25062306a36Sopenharmony_ci	unsigned int iter_flags;
25162306a36Sopenharmony_ci	unsigned int total_len = nvmet_rw_data_len(req) + req->metadata_len;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (!nvmet_check_transfer_len(req, total_len))
25462306a36Sopenharmony_ci		return;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (!req->sg_cnt) {
25762306a36Sopenharmony_ci		nvmet_req_complete(req, 0);
25862306a36Sopenharmony_ci		return;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (req->cmd->rw.opcode == nvme_cmd_write) {
26262306a36Sopenharmony_ci		opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
26362306a36Sopenharmony_ci		if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
26462306a36Sopenharmony_ci			opf |= REQ_FUA;
26562306a36Sopenharmony_ci		iter_flags = SG_MITER_TO_SG;
26662306a36Sopenharmony_ci	} else {
26762306a36Sopenharmony_ci		opf = REQ_OP_READ;
26862306a36Sopenharmony_ci		iter_flags = SG_MITER_FROM_SG;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (is_pci_p2pdma_page(sg_page(req->sg)))
27262306a36Sopenharmony_ci		opf |= REQ_NOMERGE;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (nvmet_use_inline_bvec(req)) {
27762306a36Sopenharmony_ci		bio = &req->b.inline_bio;
27862306a36Sopenharmony_ci		bio_init(bio, req->ns->bdev, req->inline_bvec,
27962306a36Sopenharmony_ci			 ARRAY_SIZE(req->inline_bvec), opf);
28062306a36Sopenharmony_ci	} else {
28162306a36Sopenharmony_ci		bio = bio_alloc(req->ns->bdev, bio_max_segs(sg_cnt), opf,
28262306a36Sopenharmony_ci				GFP_KERNEL);
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci	bio->bi_iter.bi_sector = sector;
28562306a36Sopenharmony_ci	bio->bi_private = req;
28662306a36Sopenharmony_ci	bio->bi_end_io = nvmet_bio_done;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	blk_start_plug(&plug);
28962306a36Sopenharmony_ci	if (req->metadata_len)
29062306a36Sopenharmony_ci		sg_miter_start(&prot_miter, req->metadata_sg,
29162306a36Sopenharmony_ci			       req->metadata_sg_cnt, iter_flags);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	for_each_sg(req->sg, sg, req->sg_cnt, i) {
29462306a36Sopenharmony_ci		while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
29562306a36Sopenharmony_ci				!= sg->length) {
29662306a36Sopenharmony_ci			struct bio *prev = bio;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci			if (req->metadata_len) {
29962306a36Sopenharmony_ci				rc = nvmet_bdev_alloc_bip(req, bio,
30062306a36Sopenharmony_ci							  &prot_miter);
30162306a36Sopenharmony_ci				if (unlikely(rc)) {
30262306a36Sopenharmony_ci					bio_io_error(bio);
30362306a36Sopenharmony_ci					return;
30462306a36Sopenharmony_ci				}
30562306a36Sopenharmony_ci			}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci			bio = bio_alloc(req->ns->bdev, bio_max_segs(sg_cnt),
30862306a36Sopenharmony_ci					opf, GFP_KERNEL);
30962306a36Sopenharmony_ci			bio->bi_iter.bi_sector = sector;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci			bio_chain(bio, prev);
31262306a36Sopenharmony_ci			submit_bio(prev);
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		sector += sg->length >> 9;
31662306a36Sopenharmony_ci		sg_cnt--;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (req->metadata_len) {
32062306a36Sopenharmony_ci		rc = nvmet_bdev_alloc_bip(req, bio, &prot_miter);
32162306a36Sopenharmony_ci		if (unlikely(rc)) {
32262306a36Sopenharmony_ci			bio_io_error(bio);
32362306a36Sopenharmony_ci			return;
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	submit_bio(bio);
32862306a36Sopenharmony_ci	blk_finish_plug(&plug);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic void nvmet_bdev_execute_flush(struct nvmet_req *req)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct bio *bio = &req->b.inline_bio;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (!bdev_write_cache(req->ns->bdev)) {
33662306a36Sopenharmony_ci		nvmet_req_complete(req, NVME_SC_SUCCESS);
33762306a36Sopenharmony_ci		return;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!nvmet_check_transfer_len(req, 0))
34162306a36Sopenharmony_ci		return;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	bio_init(bio, req->ns->bdev, req->inline_bvec,
34462306a36Sopenharmony_ci		 ARRAY_SIZE(req->inline_bvec), REQ_OP_WRITE | REQ_PREFLUSH);
34562306a36Sopenharmony_ci	bio->bi_private = req;
34662306a36Sopenharmony_ci	bio->bi_end_io = nvmet_bio_done;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	submit_bio(bio);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ciu16 nvmet_bdev_flush(struct nvmet_req *req)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	if (!bdev_write_cache(req->ns->bdev))
35462306a36Sopenharmony_ci		return 0;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (blkdev_issue_flush(req->ns->bdev))
35762306a36Sopenharmony_ci		return NVME_SC_INTERNAL | NVME_SC_DNR;
35862306a36Sopenharmony_ci	return 0;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic u16 nvmet_bdev_discard_range(struct nvmet_req *req,
36262306a36Sopenharmony_ci		struct nvme_dsm_range *range, struct bio **bio)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct nvmet_ns *ns = req->ns;
36562306a36Sopenharmony_ci	int ret;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	ret = __blkdev_issue_discard(ns->bdev,
36862306a36Sopenharmony_ci			nvmet_lba_to_sect(ns, range->slba),
36962306a36Sopenharmony_ci			le32_to_cpu(range->nlb) << (ns->blksize_shift - 9),
37062306a36Sopenharmony_ci			GFP_KERNEL, bio);
37162306a36Sopenharmony_ci	if (ret && ret != -EOPNOTSUPP) {
37262306a36Sopenharmony_ci		req->error_slba = le64_to_cpu(range->slba);
37362306a36Sopenharmony_ci		return errno_to_nvme_status(req, ret);
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci	return NVME_SC_SUCCESS;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic void nvmet_bdev_execute_discard(struct nvmet_req *req)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	struct nvme_dsm_range range;
38162306a36Sopenharmony_ci	struct bio *bio = NULL;
38262306a36Sopenharmony_ci	int i;
38362306a36Sopenharmony_ci	u16 status;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	for (i = 0; i <= le32_to_cpu(req->cmd->dsm.nr); i++) {
38662306a36Sopenharmony_ci		status = nvmet_copy_from_sgl(req, i * sizeof(range), &range,
38762306a36Sopenharmony_ci				sizeof(range));
38862306a36Sopenharmony_ci		if (status)
38962306a36Sopenharmony_ci			break;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		status = nvmet_bdev_discard_range(req, &range, &bio);
39262306a36Sopenharmony_ci		if (status)
39362306a36Sopenharmony_ci			break;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (bio) {
39762306a36Sopenharmony_ci		bio->bi_private = req;
39862306a36Sopenharmony_ci		bio->bi_end_io = nvmet_bio_done;
39962306a36Sopenharmony_ci		if (status)
40062306a36Sopenharmony_ci			bio_io_error(bio);
40162306a36Sopenharmony_ci		else
40262306a36Sopenharmony_ci			submit_bio(bio);
40362306a36Sopenharmony_ci	} else {
40462306a36Sopenharmony_ci		nvmet_req_complete(req, status);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void nvmet_bdev_execute_dsm(struct nvmet_req *req)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req)))
41162306a36Sopenharmony_ci		return;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	switch (le32_to_cpu(req->cmd->dsm.attributes)) {
41462306a36Sopenharmony_ci	case NVME_DSMGMT_AD:
41562306a36Sopenharmony_ci		nvmet_bdev_execute_discard(req);
41662306a36Sopenharmony_ci		return;
41762306a36Sopenharmony_ci	case NVME_DSMGMT_IDR:
41862306a36Sopenharmony_ci	case NVME_DSMGMT_IDW:
41962306a36Sopenharmony_ci	default:
42062306a36Sopenharmony_ci		/* Not supported yet */
42162306a36Sopenharmony_ci		nvmet_req_complete(req, 0);
42262306a36Sopenharmony_ci		return;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	struct nvme_write_zeroes_cmd *write_zeroes = &req->cmd->write_zeroes;
42962306a36Sopenharmony_ci	struct bio *bio = NULL;
43062306a36Sopenharmony_ci	sector_t sector;
43162306a36Sopenharmony_ci	sector_t nr_sector;
43262306a36Sopenharmony_ci	int ret;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (!nvmet_check_transfer_len(req, 0))
43562306a36Sopenharmony_ci		return;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	sector = nvmet_lba_to_sect(req->ns, write_zeroes->slba);
43862306a36Sopenharmony_ci	nr_sector = (((sector_t)le16_to_cpu(write_zeroes->length) + 1) <<
43962306a36Sopenharmony_ci		(req->ns->blksize_shift - 9));
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	ret = __blkdev_issue_zeroout(req->ns->bdev, sector, nr_sector,
44262306a36Sopenharmony_ci			GFP_KERNEL, &bio, 0);
44362306a36Sopenharmony_ci	if (bio) {
44462306a36Sopenharmony_ci		bio->bi_private = req;
44562306a36Sopenharmony_ci		bio->bi_end_io = nvmet_bio_done;
44662306a36Sopenharmony_ci		submit_bio(bio);
44762306a36Sopenharmony_ci	} else {
44862306a36Sopenharmony_ci		nvmet_req_complete(req, errno_to_nvme_status(req, ret));
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciu16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	switch (req->cmd->common.opcode) {
45562306a36Sopenharmony_ci	case nvme_cmd_read:
45662306a36Sopenharmony_ci	case nvme_cmd_write:
45762306a36Sopenharmony_ci		req->execute = nvmet_bdev_execute_rw;
45862306a36Sopenharmony_ci		if (req->sq->ctrl->pi_support && nvmet_ns_has_pi(req->ns))
45962306a36Sopenharmony_ci			req->metadata_len = nvmet_rw_metadata_len(req);
46062306a36Sopenharmony_ci		return 0;
46162306a36Sopenharmony_ci	case nvme_cmd_flush:
46262306a36Sopenharmony_ci		req->execute = nvmet_bdev_execute_flush;
46362306a36Sopenharmony_ci		return 0;
46462306a36Sopenharmony_ci	case nvme_cmd_dsm:
46562306a36Sopenharmony_ci		req->execute = nvmet_bdev_execute_dsm;
46662306a36Sopenharmony_ci		return 0;
46762306a36Sopenharmony_ci	case nvme_cmd_write_zeroes:
46862306a36Sopenharmony_ci		req->execute = nvmet_bdev_execute_write_zeroes;
46962306a36Sopenharmony_ci		return 0;
47062306a36Sopenharmony_ci	default:
47162306a36Sopenharmony_ci		return nvmet_report_invalid_opcode(req);
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci}
474