From 497ca126ddeee98b399017fbb37ea00923496e2d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 8 Apr 2025 14:22:55 -0700 Subject: [PATCH] ANDROID: scsi/sd_zbc: Support npo2 zone sizes Remove the restriction that the zone size must be a power of two. This patch has been tested with the following test script: . tests/zbd/rc . common/null_blk . common/scsi_debug DESCRIPTION="test npo2 zone size support" QUICK=1 requires() { _have_fio _have_driver f2fs _have_module_param scsi_debug zone_size_mb _have_scsi_debug } test() { echo "Running ${TEST_NAME}" local scsi_debug_params=( delay=0 dev_size_mb=1024 sector_size=4096 zbc=host-managed zone_nr_conv=0 zone_size_mb=3 ) _init_scsi_debug "${scsi_debug_params[@]}" && local zdev="/dev/${SCSI_DEBUG_DEVICES[0]}" fail && ls -ld "${zdev}" >>"${FULL}" && local fio_args=( --direct=1 --file="${zdev}" --gtod_reduce=1 --iodepth=64 --iodepth_batch=16 --ioengine=io_uring --ioscheduler=none --name=npo2zs --runtime=10 --size=1M --time_based=1 --zonemode=zbd ) && _run_fio_verify_io "${fio_args[@]}" >>"${FULL}" 2>&1 || fail=true _exit_scsi_debug if [ -z "$fail" ]; then echo "Test complete" else echo "Test failed" return 1 fi } Bug: 269471019 Bug: 415836627 Change-Id: I70b498ab8920b4e1a13e04b753fe176a632552b2 Signed-off-by: Bart Van Assche --- drivers/scsi/sd_zbc.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 6ab27f4f4878..da7e92e51b10 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -306,7 +306,7 @@ static blk_status_t sd_zbc_cmnd_checks(struct scsi_cmnd *cmd) if (sdkp->device->changed) return BLK_STS_IOERR; - if (sector & (sd_zbc_zone_sectors(sdkp) - 1)) + if (!bdev_is_zone_start(sdkp->disk->part0, sector)) /* Unaligned request */ return BLK_STS_IOERR; @@ -506,13 +506,6 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf, zone_blocks = sdkp->zone_starting_lba_gran; } - if (!is_power_of_2(zone_blocks)) { - sd_printk(KERN_ERR, sdkp, - "Zone size %llu is not a power of two.\n", - zone_blocks); - return -EINVAL; - } - *zblocks = zone_blocks; return 0; @@ -520,10 +513,13 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf, static void sd_zbc_print_zones(struct scsi_disk *sdkp) { + u64 remainder; + if (sdkp->device->type != TYPE_ZBC || !sdkp->capacity) return; - if (sdkp->capacity & (sdkp->zone_info.zone_blocks - 1)) + div64_u64_rem(sdkp->capacity, sdkp->zone_info.zone_blocks, &remainder); + if (remainder) sd_printk(KERN_NOTICE, sdkp, "%u zones of %u logical blocks + 1 runt zone\n", sdkp->zone_info.nr_zones - 1, @@ -622,7 +618,8 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, struct queue_limits *lim, if (ret != 0) goto err; - nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks); + nr_zones = div64_u64(sdkp->capacity + zone_blocks - 1, zone_blocks); + sdkp->early_zone_info.nr_zones = nr_zones; sdkp->early_zone_info.zone_blocks = zone_blocks;