diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 964eebbee14d0..85ebe13f09120 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -141,6 +141,8 @@ bool blk_integrity_merge_rq(struct request_queue *q, struct request *req, struct request *next) { struct bio_integrity_payload *bip, *bip_next; + struct blk_integrity *bi; + u64 intervals; if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0) return true; @@ -157,6 +159,13 @@ bool blk_integrity_merge_rq(struct request_queue *q, struct request *req, bip->app_tag != bip_next->app_tag) return false; + bi = blk_get_integrity(req->bio->bi_bdev->bd_disk); + intervals = blk_rq_bytes(req) >> bi->interval_exp; + if (bip->bip_flags & BIP_CHECK_REFTAG && + bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE && + bip->bip_iter.bi_sector + intervals != bip_next->bip_iter.bi_sector) + return false; + if (req->nr_integrity_segments + next->nr_integrity_segments > q->limits.max_integrity_segments) return false; @@ -171,7 +180,9 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req, struct bio *bio) { struct bio_integrity_payload *bip, *bip_bio = bio_integrity(bio); + struct blk_integrity *bi; int nr_integrity_segs; + u64 intervals; if (blk_integrity_rq(req) == 0 && bip_bio == NULL) return true; @@ -187,6 +198,13 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req, bip->app_tag != bip_bio->app_tag) return false; + bi = blk_get_integrity(req->bio->bi_bdev->bd_disk); + intervals = blk_rq_bytes(req) >> bi->interval_exp; + if (bip->bip_flags & BIP_CHECK_REFTAG && + bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE && + bip->bip_iter.bi_sector + intervals != bip_bio->bip_iter.bi_sector) + return false; + nr_integrity_segs = blk_rq_count_integrity_sg(q, bio); if (req->nr_integrity_segments + nr_integrity_segs > q->limits.max_integrity_segments) diff --git a/block/t10-pi.c b/block/t10-pi.c index a19b4e102a837..98b23345c91a8 100644 --- a/block/t10-pi.c +++ b/block/t10-pi.c @@ -546,7 +546,8 @@ static void blk_integrity_remap(struct request *rq, unsigned int nr_bytes, unsigned intervals = nr_bytes >> bi->interval_exp; struct bio *bio; - if (!(bi->flags & BLK_INTEGRITY_REF_TAG)) + if (!(bi->flags & BLK_INTEGRITY_REF_TAG) || + bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE) return; __rq_for_each_bio(bio, rq) { diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 453c1f0b2dd09..8202ca706c976 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -916,8 +916,7 @@ static void nvme_set_app_tag(struct request *req, struct nvme_command *cmnd) static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd, struct request *req) { - u32 upper, lower; - u64 ref48; + u64 ref_tag; /* only type1 and type 2 PI formats have a reftag */ switch (ns->head->pi_type) { @@ -928,18 +927,19 @@ static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd, return; } + ref_tag = full_pi_ref_tag(req); + if (blk_integrity_rq(req)) + ref_tag = bio_integrity(req->bio)->bip_iter.bi_sector; + /* both rw and write zeroes share the same reftag format */ switch (ns->head->guard_type) { case NVME_NVM_NS_16B_GUARD: - cmnd->rw.reftag = cpu_to_le32(t10_pi_ref_tag(req)); + cmnd->rw.reftag = cpu_to_le32(lower_32_bits(ref_tag)); break; case NVME_NVM_NS_64B_GUARD: - ref48 = ext_pi_ref_tag(req); - lower = lower_32_bits(ref48); - upper = upper_32_bits(ref48); - - cmnd->rw.reftag = cpu_to_le32(lower); - cmnd->rw.cdw3 = cpu_to_le32(upper); + ref_tag = lower_48_bits(ref_tag); + cmnd->rw.reftag = cpu_to_le32(lower_32_bits(ref_tag)); + cmnd->rw.cdw3 = cpu_to_le32(upper_32_bits(ref_tag)); break; default: break; @@ -1891,7 +1891,7 @@ static bool nvme_init_integrity(struct nvme_ns_head *head, break; } - bi->flags |= BLK_SPLIT_INTERVAL_CAPABLE; + bi->flags |= BLK_SPLIT_INTERVAL_CAPABLE | BLK_EXPECTED_REF_TAG_CAPABLE; bi->metadata_size = head->ms; if (bi->csum_type) { bi->pi_tuple_size = head->pi_size; diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h index b1b530613c342..45686e1665453 100644 --- a/include/linux/blk-integrity.h +++ b/include/linux/blk-integrity.h @@ -15,6 +15,8 @@ enum blk_integrity_flags { BLK_INTEGRITY_REF_TAG = 1 << 3, BLK_INTEGRITY_STACKED = 1 << 4, BLK_SPLIT_INTERVAL_CAPABLE = 1 << 5, + /* Device I/O specifies expected initial ref tag independent of LBA */ + BLK_EXPECTED_REF_TAG_CAPABLE = 1 << 6, }; const char *blk_integrity_profile_name(struct blk_integrity *bi); diff --git a/include/linux/t10-pi.h b/include/linux/t10-pi.h index b6c2496866eab..5cf4859877f50 100644 --- a/include/linux/t10-pi.h +++ b/include/linux/t10-pi.h @@ -68,9 +68,4 @@ static inline u64 lower_48_bits(u64 n) return n & ((1ull << 48) - 1); } -static inline u64 ext_pi_ref_tag(struct request *rq) -{ - return lower_48_bits(full_pi_ref_tag(rq)); -} - #endif