Using the RETURNED LOGICAL BLOCK ADDRESS field + 1 as the capacity (largest addressable LBA) if RC BASIS = 0 is wrong if there are sequential write required zones. Hence only use the RC BASIS = 0 capacity if there are no sequential write required zones. Cc: Damien Le Moal <damien.lemoal@xxxxxxx> Cc: Hannes Reinecke <hare@xxxxxxxx> Fixes: d2e428e49eec ("scsi: sd_zbc: Reduce boot device scan and revalidate time") Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx> --- drivers/scsi/sd_zbc.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 6acc4f406eb8..41ff1c0fd04b 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -699,7 +699,7 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, * * Get the device zone size and check that the device capacity as reported * by READ CAPACITY matches the max_lba value (plus one) of the report zones - * command reply for devices with RC_BASIS == 0. + * command reply. * * Returns 0 upon success or an error code upon failure. */ @@ -709,6 +709,7 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf, u64 zone_blocks; sector_t max_lba; unsigned char *rec; + u8 same; int ret; /* Do a report zone to get max_lba and the size of the first zone */ @@ -716,9 +717,26 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf, if (ret) return ret; - if (sdkp->rc_basis == 0) { - /* The max_lba field is the capacity of this device */ - max_lba = get_unaligned_be64(&buf[8]); + /* + * From ZBC-1: "If the ZONE LIST LENGTH field is zero then the SAME + * field is invalid and should be ignored by the application client." + */ + if (get_unaligned_be32(&buf[0]) == 0) { + sd_printk(KERN_INFO, sdkp, "No zones have been reported\n"); + return -EIO; + } + + same = buf[4] & 0xf; + max_lba = get_unaligned_be64(&buf[8]); + /* + * The max_lba field is the largest addressable LBA of the disk if: + * - Either RC BASIS == 1. + * - Or RC BASIS == 0, there is at least one zone in the response + * (max_lba != 0) and all zones have the same type (same == 1 || + * same == 2). + */ + if ((sdkp->rc_basis == 0 && max_lba && (same == 1 || same == 2)) || + sdkp->rc_basis == 1) { if (sdkp->capacity != max_lba + 1) { if (sdkp->first_scan) sd_printk(KERN_WARNING, sdkp,