Skip to content

Commit 7ac3c28

Browse files
Christoph Hellwigkeithbusch
authored andcommitted
nvme: fix PI insert on write
I recently ran into an issue where the PI generated using the block layer integrity code differs from that from a kernel using the PRACT fallback when the block layer integrity code is disabled, and I tracked this down to us using PRACT incorrectly. The NVM Command Set Specification (section 5.33 in 1.2, similar in older versions) specifies the PRACT insert behavior as: Inserted protection information consists of the computed CRC for the protection information format (refer to section 5.3.1) in the Guard field, the LBAT field value in the Application Tag field, the LBST field value in the Storage Tag field, if defined, and the computed reference tag in the Logical Block Reference Tag. Where the computed reference tag is defined as following for type 1 and type 2 using the text below that is duplicated in the respective bullet points: the value of the computed reference tag for the first logical block of the command is the value contained in the Initial Logical Block Reference Tag (ILBRT) or Expected Initial Logical Block Reference Tag (EILBRT) field in the command, and the computed reference tag is incremented for each subsequent logical block. So we need to set ILBRT field, but we currently don't. Interestingly this works fine on my older type 1 formatted SSD, but Qemu trips up on this. We already set ILBRT for Write Same since commit aeb7bb061be5 ("nvme: set the PRACT bit when using Write Zeroes with T10 PI"). To ease this, move the PI type check into nvme_set_ref_tag. Reviewed-by: Martin K. Petersen <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent 95a7c50 commit 7ac3c28

File tree

1 file changed

+11
-7
lines changed

1 file changed

+11
-7
lines changed

drivers/nvme/host/core.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,15 @@ static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd,
903903
u32 upper, lower;
904904
u64 ref48;
905905

906+
/* only type1 and type 2 PI formats have a reftag */
907+
switch (ns->head->pi_type) {
908+
case NVME_NS_DPS_PI_TYPE1:
909+
case NVME_NS_DPS_PI_TYPE2:
910+
break;
911+
default:
912+
return;
913+
}
914+
906915
/* both rw and write zeroes share the same reftag format */
907916
switch (ns->head->guard_type) {
908917
case NVME_NVM_NS_16B_GUARD:
@@ -942,13 +951,7 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,
942951

943952
if (nvme_ns_has_pi(ns->head)) {
944953
cmnd->write_zeroes.control |= cpu_to_le16(NVME_RW_PRINFO_PRACT);
945-
946-
switch (ns->head->pi_type) {
947-
case NVME_NS_DPS_PI_TYPE1:
948-
case NVME_NS_DPS_PI_TYPE2:
949-
nvme_set_ref_tag(ns, cmnd, req);
950-
break;
951-
}
954+
nvme_set_ref_tag(ns, cmnd, req);
952955
}
953956

954957
return BLK_STS_OK;
@@ -1039,6 +1042,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
10391042
if (WARN_ON_ONCE(!nvme_ns_has_pi(ns->head)))
10401043
return BLK_STS_NOTSUPP;
10411044
control |= NVME_RW_PRINFO_PRACT;
1045+
nvme_set_ref_tag(ns, cmnd, req);
10421046
}
10431047

10441048
if (bio_integrity_flagged(req->bio, BIP_CHECK_GUARD))

0 commit comments

Comments
 (0)