Skip to content

Commit 27ba3e8

Browse files
damien-lemoalmartinkpetersen
authored andcommitted
scsi: sd: sd_zbc: Fix handling of host-aware ZBC disks
When CONFIG_BLK_DEV_ZONED is disabled, allow using host-aware ZBC disks as regular disks. In this case, ensure that command completion is correctly executed by changing sd_zbc_complete() to return good_bytes instead of 0 and causing a hang during device probe (endless retries). When CONFIG_BLK_DEV_ZONED is enabled and a host-aware disk is detected to have partitions, it will be used as a regular disk. In this case, make sure to not do anything in sd_zbc_revalidate_zones() as that triggers warnings. Since all these different cases result in subtle settings of the disk queue zoned model, introduce the block layer helper function blk_queue_set_zoned() to generically implement setting up the effective zoned model according to the disk type, the presence of partitions on the disk and CONFIG_BLK_DEV_ZONED configuration. Link: https://lore.kernel.org/r/20200915073347.832424-2-damien.lemoal@wdc.com Fixes: b720530 ("block: allow partitions on host aware zone devices") Cc: <stable@vger.kernel.org> Reported-by: Borislav Petkov <bp@alien8.de> Suggested-by: Christoph Hellwig <hch@infradead.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 7f04839 commit 27ba3e8

5 files changed

Lines changed: 72 additions & 14 deletions

File tree

block/blk-settings.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,52 @@ bool blk_queue_can_use_dma_map_merging(struct request_queue *q,
801801
}
802802
EXPORT_SYMBOL_GPL(blk_queue_can_use_dma_map_merging);
803803

804+
/**
805+
* blk_queue_set_zoned - configure a disk queue zoned model.
806+
* @disk: the gendisk of the queue to configure
807+
* @model: the zoned model to set
808+
*
809+
* Set the zoned model of the request queue of @disk according to @model.
810+
* When @model is BLK_ZONED_HM (host managed), this should be called only
811+
* if zoned block device support is enabled (CONFIG_BLK_DEV_ZONED option).
812+
* If @model specifies BLK_ZONED_HA (host aware), the effective model used
813+
* depends on CONFIG_BLK_DEV_ZONED settings and on the existence of partitions
814+
* on the disk.
815+
*/
816+
void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
817+
{
818+
switch (model) {
819+
case BLK_ZONED_HM:
820+
/*
821+
* Host managed devices are supported only if
822+
* CONFIG_BLK_DEV_ZONED is enabled.
823+
*/
824+
WARN_ON_ONCE(!IS_ENABLED(CONFIG_BLK_DEV_ZONED));
825+
break;
826+
case BLK_ZONED_HA:
827+
/*
828+
* Host aware devices can be treated either as regular block
829+
* devices (similar to drive managed devices) or as zoned block
830+
* devices to take advantage of the zone command set, similarly
831+
* to host managed devices. We try the latter if there are no
832+
* partitions and zoned block device support is enabled, else
833+
* we do nothing special as far as the block layer is concerned.
834+
*/
835+
if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) ||
836+
disk_has_partitions(disk))
837+
model = BLK_ZONED_NONE;
838+
break;
839+
case BLK_ZONED_NONE:
840+
default:
841+
if (WARN_ON_ONCE(model != BLK_ZONED_NONE))
842+
model = BLK_ZONED_NONE;
843+
break;
844+
}
845+
846+
disk->queue->limits.zoned = model;
847+
}
848+
EXPORT_SYMBOL_GPL(blk_queue_set_zoned);
849+
804850
static int __init blk_settings_init(void)
805851
{
806852
blk_max_low_pfn = max_low_pfn - 1;

drivers/scsi/sd.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,26 +2964,32 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
29642964

29652965
if (sdkp->device->type == TYPE_ZBC) {
29662966
/* Host-managed */
2967-
q->limits.zoned = BLK_ZONED_HM;
2967+
blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HM);
29682968
} else {
29692969
sdkp->zoned = (buffer[8] >> 4) & 3;
2970-
if (sdkp->zoned == 1 && !disk_has_partitions(sdkp->disk)) {
2970+
if (sdkp->zoned == 1) {
29712971
/* Host-aware */
2972-
q->limits.zoned = BLK_ZONED_HA;
2972+
blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HA);
29732973
} else {
2974-
/*
2975-
* Treat drive-managed devices and host-aware devices
2976-
* with partitions as regular block devices.
2977-
*/
2978-
q->limits.zoned = BLK_ZONED_NONE;
2979-
if (sdkp->zoned == 2 && sdkp->first_scan)
2980-
sd_printk(KERN_NOTICE, sdkp,
2981-
"Drive-managed SMR disk\n");
2974+
/* Regular disk or drive managed disk */
2975+
blk_queue_set_zoned(sdkp->disk, BLK_ZONED_NONE);
29822976
}
29832977
}
2984-
if (blk_queue_is_zoned(q) && sdkp->first_scan)
2978+
2979+
if (!sdkp->first_scan)
2980+
goto out;
2981+
2982+
if (blk_queue_is_zoned(q)) {
29852983
sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n",
29862984
q->limits.zoned == BLK_ZONED_HM ? "managed" : "aware");
2985+
} else {
2986+
if (sdkp->zoned == 1)
2987+
sd_printk(KERN_NOTICE, sdkp,
2988+
"Host-aware SMR disk used as regular disk\n");
2989+
else if (sdkp->zoned == 2)
2990+
sd_printk(KERN_NOTICE, sdkp,
2991+
"Drive-managed SMR disk\n");
2992+
}
29872993

29882994
out:
29892995
kfree(buffer);

drivers/scsi/sd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ static inline blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd,
259259
static inline unsigned int sd_zbc_complete(struct scsi_cmnd *cmd,
260260
unsigned int good_bytes, struct scsi_sense_hdr *sshdr)
261261
{
262-
return 0;
262+
return good_bytes;
263263
}
264264

265265
static inline blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd,

drivers/scsi/sd_zbc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,11 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
667667
u32 max_append;
668668
int ret = 0;
669669

670-
if (!sd_is_zoned(sdkp))
670+
/*
671+
* There is nothing to do for regular disks, including host-aware disks
672+
* that have partitions.
673+
*/
674+
if (!blk_queue_is_zoned(q))
671675
return 0;
672676

673677
/*

include/linux/blkdev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ struct queue_limits {
352352
typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx,
353353
void *data);
354354

355+
void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model);
356+
355357
#ifdef CONFIG_BLK_DEV_ZONED
356358

357359
#define BLK_ALL_ZONES ((unsigned int)-1)

0 commit comments

Comments
 (0)