Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-block.git] / drivers / scsi / sd_zbc.c
index 87a7274e4632b4f3e9201beefd090b634bb90ee0..ee558675eab4aa862850dd86a620570e1e4fe98a 100644 (file)
@@ -665,12 +665,28 @@ static int sd_zbc_init_disk(struct scsi_disk *sdkp)
        return 0;
 }
 
-void sd_zbc_release_disk(struct scsi_disk *sdkp)
+static void sd_zbc_clear_zone_info(struct scsi_disk *sdkp)
 {
+       /* Serialize against revalidate zones */
+       mutex_lock(&sdkp->rev_mutex);
+
        kvfree(sdkp->zones_wp_offset);
        sdkp->zones_wp_offset = NULL;
        kfree(sdkp->zone_wp_update_buf);
        sdkp->zone_wp_update_buf = NULL;
+
+       sdkp->nr_zones = 0;
+       sdkp->rev_nr_zones = 0;
+       sdkp->zone_blocks = 0;
+       sdkp->rev_zone_blocks = 0;
+
+       mutex_unlock(&sdkp->rev_mutex);
+}
+
+void sd_zbc_release_disk(struct scsi_disk *sdkp)
+{
+       if (sd_is_zoned(sdkp))
+               sd_zbc_clear_zone_info(sdkp);
 }
 
 static void sd_zbc_revalidate_zones_cb(struct gendisk *disk)
@@ -773,6 +789,21 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
                 */
                return 0;
 
+       /* READ16/WRITE16 is mandatory for ZBC disks */
+       sdkp->device->use_16_for_rw = 1;
+       sdkp->device->use_10_for_rw = 0;
+
+       if (!blk_queue_is_zoned(q)) {
+               /*
+                * This can happen for a host aware disk with partitions.
+                * The block device zone information was already cleared
+                * by blk_queue_set_zoned(). Only clear the scsi disk zone
+                * information and exit early.
+                */
+               sd_zbc_clear_zone_info(sdkp);
+               return 0;
+       }
+
        /* Check zoned block device characteristics (unconstrained reads) */
        ret = sd_zbc_check_zoned_characteristics(sdkp, buf);
        if (ret)
@@ -793,9 +824,13 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
        blk_queue_max_active_zones(q, 0);
        nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks);
 
-       /* READ16/WRITE16 is mandatory for ZBC disks */
-       sdkp->device->use_16_for_rw = 1;
-       sdkp->device->use_10_for_rw = 0;
+       /*
+        * Per ZBC and ZAC specifications, writes in sequential write required
+        * zones of host-managed devices must be aligned to the device physical
+        * block size.
+        */
+       if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
+               blk_queue_zone_write_granularity(q, sdkp->physical_block_size);
 
        sdkp->rev_nr_zones = nr_zones;
        sdkp->rev_zone_blocks = zone_blocks;