NVMe Read, Write, and Write Zeroes commands include an (E)ILBRT field to specify the expected initial reference tag for the controller to check against the ref tags in the protection information buffer. However, the NVMe driver currently always sets (E)ILBRT to the lower bits of the LBA. The block integrity layer generates/verifies the PI ref tags according to the bio's ref tag seed, so it must "remap" the ref tags, adjusting for the difference between the ref tag seed and the absolute integrity interval number (= LBA). If a request has an integrity payload, set (E)ILBRT to its ref tag seed so no ref tag remapping is required. Set BLK_EXPECTED_REF_TAG_CAPABLE in NVMe devices' enum blk_integrity_flags to skip the block integrity layer ref tag remapping. Signed-off-by: Caleb Sander Mateos --- drivers/nvme/host/core.c | 20 ++++++++++---------- include/linux/t10-pi.h | 5 ----- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 453c1f0b2dd0..8202ca706c97 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -914,34 +914,34 @@ 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) { case NVME_NS_DPS_PI_TYPE1: case NVME_NS_DPS_PI_TYPE2: break; default: 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; } } @@ -1889,11 +1889,11 @@ static bool nvme_init_integrity(struct nvme_ns_head *head, break; default: 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; bi->pi_offset = info->pi_offset; } diff --git a/include/linux/t10-pi.h b/include/linux/t10-pi.h index b6c2496866ea..5cf4859877f5 100644 --- a/include/linux/t10-pi.h +++ b/include/linux/t10-pi.h @@ -66,11 +66,6 @@ struct crc64_pi_tuple { 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 -- 2.54.0