scsi: sd: Update DIX config every time sd_revalidate_disk() is called

If a controller has DIX is enabled and an attached disk is formatted using
a protection type supported by the controller, a block integrity profile is
registered to enable protected transfers.

If the disk is subsequently reformatted to disable PI, and the controller
does not support DIX Type 0, this can lead to failures such as this:

[142829.032340] hisi_sas_v3_hw 0000:b4:04.0: erroneous completion iptt=2375 task=00000000bea0970c dev id=5 direct-attached phy4 addr=51c20dbaf642a000 CQ hdr: 0x1023 0x50947 0x0 0x20000 Error info: 0x0 0x0 0x4 0x0
[142829.073883] sas: Enter sas_scsi_recover_host busy: 1 failed: 1
[142829.079783] sas: sas_scsi_find_task: aborting task 0x00000000bea0970c
[142829.102342] sas: Internal abort: task to dev 51c20dbaf642a000 response: 0x0 status 0x5
[142829.110319] sas: sas_eh_handle_sas_errors: task 0x00000000bea0970c is done
[142829.117275] sd 7:0:5:0: [sdc] tag#2375 UNKNOWN(0x2003) Result: hostbyte=0x05 driverbyte=DRIVER_OK cmd_age=0s
[142829.127171] sd 7:0:5:0: [sdc] tag#2375 CDB: opcode=0x2a 2a 00 00 00 00 00 00 00 08 00
[142829.135059] I/O error, dev sdc, sector 0 op 0x1:(WRITE) flags 0x18800 phys_seg 1 prio class 2

This is because the block layer integrity profile is currently only set up
the first time a disk is discovered.

To address this, remove the first_scan check when configuring protection
information during revalidate. Also unregister the block integrity profile
if DIX is not supported with a given protection type.

[mkp: commit description + printk dedup]

Link: https://lore.kernel.org/r/20230221081026.24736-1-yangxingui@huawei.com
Signed-off-by: Xingui Yang <yangxingui@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Xingui Yang 2023-02-21 08:10:26 +00:00 committed by Martin K. Petersen
parent 2b3795167e
commit 26a02d972b
2 changed files with 11 additions and 12 deletions

View File

@ -2253,23 +2253,20 @@ static void sd_config_protection(struct scsi_disk *sdkp)
{
struct scsi_device *sdp = sdkp->device;
if (!sdkp->first_scan)
return;
sd_dif_config_host(sdkp);
if (!sdkp->protection_type)
return;
if (!scsi_host_dif_capable(sdp->host, sdkp->protection_type)) {
sd_printk(KERN_NOTICE, sdkp,
"Disabling DIF Type %u protection\n",
sdkp->protection_type);
sd_first_printk(KERN_NOTICE, sdkp,
"Disabling DIF Type %u protection\n",
sdkp->protection_type);
sdkp->protection_type = 0;
}
sd_printk(KERN_NOTICE, sdkp, "Enabling DIF Type %u protection\n",
sdkp->protection_type);
sd_first_printk(KERN_NOTICE, sdkp, "Enabling DIF Type %u protection\n",
sdkp->protection_type);
}
static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,

View File

@ -39,8 +39,10 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
dif = 0; dix = 1;
}
if (!dix)
if (!dix) {
blk_integrity_unregister(disk);
return;
}
memset(&bi, 0, sizeof(bi));
@ -72,9 +74,9 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
bi.tag_size = sizeof(u16);
}
sd_printk(KERN_NOTICE, sdkp,
"Enabling DIX %s, application tag size %u bytes\n",
bi.profile->name, bi.tag_size);
sd_first_printk(KERN_NOTICE, sdkp,
"Enabling DIX %s, application tag size %u bytes\n",
bi.profile->name, bi.tag_size);
out:
blk_integrity_register(disk, &bi);
}