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