[PATCH 3/3] scsi: sd_zbc: Fix handling of RC BASIS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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,



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux