From: James Bottomley Date: Tue, 27 Mar 2018 16:27:34 +0000 (-0400) Subject: Merge branch 'fixes' into misc X-Git-Tag: v4.17-rc1~112^2 X-Git-Url: https://repo.jachan.dev/J-linux.git/commitdiff_plain/2e1f44f6ad8008be353c7c99286f7a747b4b3cf4 Merge branch 'fixes' into misc Somewhat nasty merge due to conflicts between "33b28357dd00 scsi: qla2xxx: Fix Async GPN_FT for FCP and FC-NVMe scan" and "2b5b96473efc scsi: qla2xxx: Fix FC-NVMe LUN discovery" Merge is non-trivial and has been verified by Qlogic (Cavium) Signed-off-by: James E.J. Bottomley --- 2e1f44f6ad8008be353c7c99286f7a747b4b3cf4 diff --cc drivers/scsi/sd_zbc.c index 8f3669fd490d,9049a189c8e5..41df75eea57b --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@@ -494,133 -569,20 +486,136 @@@ out if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Zone size too large\n"); - return -ENODEV; + ret = -ENODEV; + } else { + sdkp->zone_blocks = zone_blocks; + sdkp->zone_shift = ilog2(zone_blocks); } - sdkp->zone_blocks = zone_blocks; - sdkp->zone_shift = ilog2(zone_blocks); + out_free: + kfree(buf); - return 0; + return ret; } +/** + * sd_zbc_alloc_zone_bitmap - Allocate a zone bitmap (one bit per zone). + * @sdkp: The disk of the bitmap + */ +static inline unsigned long *sd_zbc_alloc_zone_bitmap(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + + return kzalloc_node(BITS_TO_LONGS(sdkp->nr_zones) + * sizeof(unsigned long), + GFP_KERNEL, q->node); +} + +/** + * sd_zbc_get_seq_zones - Parse report zones reply to identify sequential zones + * @sdkp: disk used + * @buf: report reply buffer + * @buflen: length of @buf + * @seq_zones_bitmap: bitmap of sequential zones to set + * + * Parse reported zone descriptors in @buf to identify sequential zones and + * set the reported zone bit in @seq_zones_bitmap accordingly. + * Since read-only and offline zones cannot be written, do not + * mark them as sequential in the bitmap. + * Return the LBA after the last zone reported. + */ +static sector_t sd_zbc_get_seq_zones(struct scsi_disk *sdkp, unsigned char *buf, + unsigned int buflen, + unsigned long *seq_zones_bitmap) +{ + sector_t lba, next_lba = sdkp->capacity; + unsigned int buf_len, list_length; + unsigned char *rec; + u8 type, cond; + + list_length = get_unaligned_be32(&buf[0]) + 64; + buf_len = min(list_length, buflen); + rec = buf + 64; + + while (rec < buf + buf_len) { + type = rec[0] & 0x0f; + cond = (rec[1] >> 4) & 0xf; + lba = get_unaligned_be64(&rec[16]); + if (type != ZBC_ZONE_TYPE_CONV && + cond != ZBC_ZONE_COND_READONLY && + cond != ZBC_ZONE_COND_OFFLINE) + set_bit(lba >> sdkp->zone_shift, seq_zones_bitmap); + next_lba = lba + get_unaligned_be64(&rec[8]); + rec += 64; + } + + return next_lba; +} + +/** + * sd_zbc_setup_seq_zones_bitmap - Initialize the disk seq zone bitmap. + * @sdkp: target disk + * + * Allocate a zone bitmap and initialize it by identifying sequential zones. + */ +static int sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + unsigned long *seq_zones_bitmap; + sector_t lba = 0; + unsigned char *buf; + int ret = -ENOMEM; + + seq_zones_bitmap = sd_zbc_alloc_zone_bitmap(sdkp); + if (!seq_zones_bitmap) + return -ENOMEM; + + buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); + if (!buf) + goto out; + + while (lba < sdkp->capacity) { + ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba); + if (ret) + goto out; + lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE, + seq_zones_bitmap); + } + + if (lba != sdkp->capacity) { + /* Something went wrong */ + ret = -EIO; + } + +out: + kfree(buf); + if (ret) { + kfree(seq_zones_bitmap); + return ret; + } + + q->seq_zones_bitmap = seq_zones_bitmap; + + return 0; +} + +static void sd_zbc_cleanup(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + + kfree(q->seq_zones_bitmap); + q->seq_zones_bitmap = NULL; + + kfree(q->seq_zones_wlock); + q->seq_zones_wlock = NULL; + + q->nr_zones = 0; +} + static int sd_zbc_setup(struct scsi_disk *sdkp) { + struct request_queue *q = sdkp->disk->queue; + int ret; /* READ16/WRITE16 is mandatory for ZBC disks */ sdkp->device->use_16_for_rw = 1;