for-linus-20181026

-----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAlvTOPAQHGF4Ym9lQGtl
 cm5lbC5kawAKCRD301j7KXHgptS3D/9jUjcOiMWYwHW6UbLGlVJiW9igzl6xSKpL
 QSxVCyxKoiaoMobO5dg/BJSq9grQAeOAzv0cjGS6VUuUtfRzMlar73PqZzeaF3oE
 oXeg1goxd9Qjs5AgJ5m3ZM+PLIn7g1zh5TP9vKKGeV4USh4tTlLgYEm5Su3sJDLb
 +6RSCkzYahSCouV2ugHPscsroJ/xzbT5vpMvSflbpe5iYNwzRcn81Z/c6rz7nw9A
 IlnYaf9EdP33uyP1j5Elc2Q1q5DmmxePJlrCUc8VyQdVSMAFZBWZfnkAsdeG7i5V
 YLtNm8tfmGNBZQ0Izp/VwGf9ZMwy13Z2JLBYK/qUh2EGGaWzk7FxiPR9+Gl2MHCD
 iRL7ujDb8yJGL8IEz6xiLcZEHZtUW1VLKPA/YiVtBrg9i6533KEboSQ77CyPchxc
 JJaowruaw/TmaL0MdLYQ3MHVYolWjljyv36YqJcN4oeaGuWfOSotjKKSnIg6FAh3
 Co8cDdcrGdD3yUYGx/7NR+/ejfWDnlCMJ/MtWmC0SMiJbL0pQgjIhXdyt1ciJB5Z
 ezHHrGahbmwNg27AuVHlVsjD8jmA2Z017NnS4zNHOdwNAuhE1LWtBOGU8I5oytJH
 eH0UYu2TDjhPGZ7TjEGZ0Xo6brz6IgPOaUIxrUj73hnbSunxdxo2jODFiiiMrs7Z
 6fxyHKMPuQ==
 =NFEB
 -----END PGP SIGNATURE-----

Merge tag 'for-linus-20181026' of git://git.kernel.dk/linux-block

Pull more block layer updates from Jens Axboe:

 - Set of patches improving support for zoned devices. This was ready
   before the merge window, but I was late in picking it up and hence it
   missed the original pull request (Damien, Christoph)

 - libata no link power management quirk addition for a Samsung drive
   (Diego Viola)

 - Fix for a performance regression in BFQ that went into this merge
   window (Federico Motta)

 - Fix for a missing dma mask setting return value check (Gustavo)

 - Typo in the gdrom queue failure case (me)

 - NULL pointer deref fix for xen-blkfront (Vasilis Liaskovitis)

 - Fixing the get_rq trace point placement in blk-mq (Xiaoguang Wang)

 - Removal of a set-but-not-read variable in cdrom (zhong jiang)

* tag 'for-linus-20181026' of git://git.kernel.dk/linux-block:
  libata: Apply NOLPM quirk for SAMSUNG MZ7TD256HAFV-000L9
  block, bfq: fix asymmetric scenarios detection
  gdrom: fix mistake in assignment of error
  blk-mq: place trace_block_getrq() in correct place
  block: Introduce blk_revalidate_disk_zones()
  block: add a report_zones method
  block: Expose queue nr_zones in sysfs
  block: Improve zone reset execution
  block: Introduce BLKGETNRZONES ioctl
  block: Introduce BLKGETZONESZ ioctl
  block: Limit allocation of zone descriptors for report zones
  block: Introduce blkdev_nr_zones() helper
  scsi: sd_zbc: Fix sd_zbc_check_zones() error checks
  scsi: sd_zbc: Reduce boot device scan and revalidate time
  scsi: sd_zbc: Rearrange code
  cdrom: remove set but not used variable 'tocuse'
  skd: fix unchecked return values
  xen/blkfront: avoid NULL blkfront_info dereference on device removal
This commit is contained in:
Linus Torvalds 2018-10-26 12:43:13 -07:00
commit 6080ad3a99
29 changed files with 620 additions and 741 deletions

View file

@ -1272,8 +1272,6 @@ static int sd_init_command(struct scsi_cmnd *cmd)
case REQ_OP_READ:
case REQ_OP_WRITE:
return sd_setup_read_write_cmnd(cmd);
case REQ_OP_ZONE_REPORT:
return sd_zbc_setup_report_cmnd(cmd);
case REQ_OP_ZONE_RESET:
return sd_zbc_setup_reset_cmnd(cmd);
default:
@ -1802,6 +1800,7 @@ static const struct block_device_operations sd_fops = {
.check_events = sd_check_events,
.revalidate_disk = sd_revalidate_disk,
.unlock_native_capacity = sd_unlock_native_capacity,
.report_zones = sd_zbc_report_zones,
.pr_ops = &sd_pr_ops,
};
@ -1953,16 +1952,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
scsi_set_resid(SCpnt, blk_rq_bytes(req));
}
break;
case REQ_OP_ZONE_REPORT:
if (!result) {
good_bytes = scsi_bufflen(SCpnt)
- scsi_get_resid(SCpnt);
scsi_set_resid(SCpnt, 0);
} else {
good_bytes = 0;
scsi_set_resid(SCpnt, blk_rq_bytes(req));
}
break;
default:
/*
* In case of bogus fw or device, we could end up having
@ -3425,8 +3414,6 @@ static int sd_remove(struct device *dev)
del_gendisk(sdkp->disk);
sd_shutdown(dev);
sd_zbc_remove(sdkp);
free_opal_dev(sdkp->opal_dev);
blk_register_region(devt, SD_MINORS, NULL,

View file

@ -76,7 +76,6 @@ struct scsi_disk {
#ifdef CONFIG_BLK_DEV_ZONED
u32 nr_zones;
u32 zone_blocks;
u32 zone_shift;
u32 zones_optimal_open;
u32 zones_optimal_nonseq;
u32 zones_max_open;
@ -271,12 +270,13 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp)
#ifdef CONFIG_BLK_DEV_ZONED
extern int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer);
extern void sd_zbc_remove(struct scsi_disk *sdkp);
extern void sd_zbc_print_zones(struct scsi_disk *sdkp);
extern int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd);
extern int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd);
extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
struct scsi_sense_hdr *sshdr);
extern int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
struct blk_zone *zones, unsigned int *nr_zones,
gfp_t gfp_mask);
#else /* CONFIG_BLK_DEV_ZONED */
@ -286,15 +286,8 @@ static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
return 0;
}
static inline void sd_zbc_remove(struct scsi_disk *sdkp) {}
static inline void sd_zbc_print_zones(struct scsi_disk *sdkp) {}
static inline int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd)
{
return BLKPREP_INVALID;
}
static inline int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd)
{
return BLKPREP_INVALID;
@ -304,6 +297,8 @@ static inline void sd_zbc_complete(struct scsi_cmnd *cmd,
unsigned int good_bytes,
struct scsi_sense_hdr *sshdr) {}
#define sd_zbc_report_zones NULL
#endif /* CONFIG_BLK_DEV_ZONED */
#endif /* _SCSI_DISK_H */

View file

@ -62,16 +62,22 @@ static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
}
/**
* sd_zbc_report_zones - Issue a REPORT ZONES scsi command.
* sd_zbc_do_report_zones - Issue a REPORT ZONES scsi command.
* @sdkp: The target disk
* @buf: Buffer to use for the reply
* @buflen: the buffer size
* @lba: Start LBA of the report
* @partial: Do partial report
*
* For internal use during device validation.
* Using partial=true can significantly speed up execution of a report zones
* command because the disk does not have to count all possible report matching
* zones and will only report the count of zones fitting in the command reply
* buffer.
*/
static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
unsigned int buflen, sector_t lba)
static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
unsigned int buflen, sector_t lba,
bool partial)
{
struct scsi_device *sdp = sdkp->device;
const int timeout = sdp->request_queue->rq_timeout;
@ -85,6 +91,8 @@ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
cmd[1] = ZI_REPORT_ZONES;
put_unaligned_be64(lba, &cmd[2]);
put_unaligned_be32(buflen, &cmd[10]);
if (partial)
cmd[14] = ZBC_REPORT_ZONE_PARTIAL;
memset(buf, 0, buflen);
result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
@ -110,108 +118,56 @@ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
}
/**
* sd_zbc_setup_report_cmnd - Prepare a REPORT ZONES scsi command
* @cmd: The command to setup
* sd_zbc_report_zones - Disk report zones operation.
* @disk: The target disk
* @sector: Start 512B sector of the report
* @zones: Array of zone descriptors
* @nr_zones: Number of descriptors in the array
* @gfp_mask: Memory allocation mask
*
* Call in sd_init_command() for a REQ_OP_ZONE_REPORT request.
* Execute a report zones command on the target disk.
*/
int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd)
int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
struct blk_zone *zones, unsigned int *nr_zones,
gfp_t gfp_mask)
{
struct request *rq = cmd->request;
struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
sector_t lba, sector = blk_rq_pos(rq);
unsigned int nr_bytes = blk_rq_bytes(rq);
int ret;
WARN_ON(nr_bytes == 0);
struct scsi_disk *sdkp = scsi_disk(disk);
unsigned int i, buflen, nrz = *nr_zones;
unsigned char *buf;
size_t offset = 0;
int ret = 0;
if (!sd_is_zoned(sdkp))
/* Not a zoned device */
return BLKPREP_KILL;
return -EOPNOTSUPP;
ret = scsi_init_io(cmd);
if (ret != BLKPREP_OK)
return ret;
/*
* Get a reply buffer for the number of requested zones plus a header.
* For ATA, buffers must be aligned to 512B.
*/
buflen = roundup((nrz + 1) * 64, 512);
buf = kmalloc(buflen, gfp_mask);
if (!buf)
return -ENOMEM;
cmd->cmd_len = 16;
memset(cmd->cmnd, 0, cmd->cmd_len);
cmd->cmnd[0] = ZBC_IN;
cmd->cmnd[1] = ZI_REPORT_ZONES;
lba = sectors_to_logical(sdkp->device, sector);
put_unaligned_be64(lba, &cmd->cmnd[2]);
put_unaligned_be32(nr_bytes, &cmd->cmnd[10]);
/* Do partial report for speeding things up */
cmd->cmnd[14] = ZBC_REPORT_ZONE_PARTIAL;
cmd->sc_data_direction = DMA_FROM_DEVICE;
cmd->sdb.length = nr_bytes;
cmd->transfersize = sdkp->device->sector_size;
cmd->allowed = 0;
return BLKPREP_OK;
}
/**
* sd_zbc_report_zones_complete - Process a REPORT ZONES scsi command reply.
* @scmd: The completed report zones command
* @good_bytes: reply size in bytes
*
* Convert all reported zone descriptors to struct blk_zone. The conversion
* is done in-place, directly in the request specified sg buffer.
*/
static void sd_zbc_report_zones_complete(struct scsi_cmnd *scmd,
unsigned int good_bytes)
{
struct request *rq = scmd->request;
struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
struct sg_mapping_iter miter;
struct blk_zone_report_hdr hdr;
struct blk_zone zone;
unsigned int offset, bytes = 0;
unsigned long flags;
u8 *buf;
if (good_bytes < 64)
return;
memset(&hdr, 0, sizeof(struct blk_zone_report_hdr));
sg_miter_start(&miter, scsi_sglist(scmd), scsi_sg_count(scmd),
SG_MITER_TO_SG | SG_MITER_ATOMIC);
local_irq_save(flags);
while (sg_miter_next(&miter) && bytes < good_bytes) {
buf = miter.addr;
offset = 0;
if (bytes == 0) {
/* Set the report header */
hdr.nr_zones = min_t(unsigned int,
(good_bytes - 64) / 64,
get_unaligned_be32(&buf[0]) / 64);
memcpy(buf, &hdr, sizeof(struct blk_zone_report_hdr));
offset += 64;
bytes += 64;
}
/* Parse zone descriptors */
while (offset < miter.length && hdr.nr_zones) {
WARN_ON(offset > miter.length);
buf = miter.addr + offset;
sd_zbc_parse_report(sdkp, buf, &zone);
memcpy(buf, &zone, sizeof(struct blk_zone));
offset += 64;
bytes += 64;
hdr.nr_zones--;
}
if (!hdr.nr_zones)
break;
ret = sd_zbc_do_report_zones(sdkp, buf, buflen,
sectors_to_logical(sdkp->device, sector), true);
if (ret)
goto out_free_buf;
nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64);
for (i = 0; i < nrz; i++) {
offset += 64;
sd_zbc_parse_report(sdkp, buf + offset, zones);
zones++;
}
sg_miter_stop(&miter);
local_irq_restore(flags);
*nr_zones = nrz;
out_free_buf:
kfree(buf);
return ret;
}
/**
@ -294,30 +250,23 @@ void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
case REQ_OP_WRITE_ZEROES:
case REQ_OP_WRITE_SAME:
break;
case REQ_OP_ZONE_REPORT:
if (!result)
sd_zbc_report_zones_complete(cmd, good_bytes);
break;
}
}
/**
* sd_zbc_read_zoned_characteristics - Read zoned block device characteristics
* sd_zbc_check_zoned_characteristics - Check zoned block device characteristics
* @sdkp: Target disk
* @buf: Buffer where to store the VPD page data
*
* Read VPD page B6.
* Read VPD page B6, get information and check that reads are unconstrained.
*/
static int sd_zbc_read_zoned_characteristics(struct scsi_disk *sdkp,
unsigned char *buf)
static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
unsigned char *buf)
{
if (scsi_get_vpd_page(sdkp->device, 0xb6, buf, 64)) {
sd_printk(KERN_NOTICE, sdkp,
"Unconstrained-read check failed\n");
"Read zoned characteristics VPD page failed\n");
return -ENODEV;
}
@ -335,43 +284,17 @@ static int sd_zbc_read_zoned_characteristics(struct scsi_disk *sdkp,
sdkp->zones_max_open = get_unaligned_be32(&buf[16]);
}
return 0;
}
/**
* sd_zbc_check_capacity - Check reported capacity.
* @sdkp: Target disk
* @buf: Buffer to use for commands
*
* ZBC drive may report only the capacity of the first conventional zones at
* LBA 0. This is indicated by the RC_BASIS field of the read capacity reply.
* Check this here. If the disk reported only its conventional zones capacity,
* get the total capacity by doing a report zones.
*/
static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
{
sector_t lba;
int ret;
if (sdkp->rc_basis != 0)
return 0;
/* Do a report zone to get the maximum LBA to check capacity */
ret = sd_zbc_report_zones(sdkp, buf, SD_BUF_SIZE, 0);
if (ret)
return ret;
/* The max_lba field is the capacity of this device */
lba = get_unaligned_be64(&buf[8]);
if (lba + 1 == sdkp->capacity)
return 0;
if (sdkp->first_scan)
sd_printk(KERN_WARNING, sdkp,
"Changing capacity from %llu to max LBA+1 %llu\n",
(unsigned long long)sdkp->capacity,
(unsigned long long)lba + 1);
sdkp->capacity = lba + 1;
/*
* Check for unconstrained reads: host-managed devices with
* constrained reads (drives failing read after write pointer)
* are not supported.
*/
if (!sdkp->urswrz) {
if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp,
"constrained reads devices are not supported\n");
return -ENODEV;
}
return 0;
}
@ -379,24 +302,27 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
#define SD_ZBC_BUF_SIZE 131072U
/**
* sd_zbc_check_zone_size - Check the device zone sizes
* sd_zbc_check_zones - Check the device capacity and zone sizes
* @sdkp: Target disk
*
* Check that all zones of the device are equal. The last zone can however
* be smaller. The zone size must also be a power of two number of LBAs.
* Check that the device capacity as reported by READ CAPACITY matches the
* max_lba value (plus one)of the report zones command reply. Also check that
* all zones of the device have an equal size, only allowing the last zone of
* the disk to have a smaller size (runt zone). The zone size must also be a
* power of two.
*
* Returns the zone size in number of blocks upon success or an error code
* upon failure.
*/
static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks)
{
u64 zone_blocks = 0;
sector_t block = 0;
sector_t max_lba, block = 0;
unsigned char *buf;
unsigned char *rec;
unsigned int buf_len;
unsigned int list_length;
s64 ret;
int ret;
u8 same;
/* Get a buffer */
@ -404,11 +330,28 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
if (!buf)
return -ENOMEM;
/* Do a report zone to get the same field */
ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0);
/* Do a report zone to get max_lba and the same field */
ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false);
if (ret)
goto out_free;
if (sdkp->rc_basis == 0) {
/* The max_lba field is the capacity of this device */
max_lba = get_unaligned_be64(&buf[8]);
if (sdkp->capacity != max_lba + 1) {
if (sdkp->first_scan)
sd_printk(KERN_WARNING, sdkp,
"Changing capacity from %llu to max LBA+1 %llu\n",
(unsigned long long)sdkp->capacity,
(unsigned long long)max_lba + 1);
sdkp->capacity = max_lba + 1;
}
}
/*
* Check same field: for any value other than 0, we know that all zones
* have the same size.
*/
same = buf[4] & 0x0f;
if (same > 0) {
rec = &buf[64];
@ -445,8 +388,8 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
}
if (block < sdkp->capacity) {
ret = sd_zbc_report_zones(sdkp, buf,
SD_ZBC_BUF_SIZE, block);
ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
block, true);
if (ret)
goto out_free;
}
@ -470,9 +413,10 @@ out:
if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp,
"Zone size too large\n");
ret = -ENODEV;
ret = -EFBIG;
} else {
ret = zone_blocks;
*zblocks = zone_blocks;
ret = 0;
}
out_free:
@ -481,191 +425,11 @@ out_free:
return ret;
}
/**
* sd_zbc_alloc_zone_bitmap - Allocate a zone bitmap (one bit per zone).
* @nr_zones: Number of zones to allocate space for.
* @numa_node: NUMA node to allocate the memory from.
*/
static inline unsigned long *
sd_zbc_alloc_zone_bitmap(u32 nr_zones, int numa_node)
{
return kcalloc_node(BITS_TO_LONGS(nr_zones), sizeof(unsigned long),
GFP_KERNEL, numa_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
* @zone_shift: logarithm base 2 of the number of blocks in a zone
* @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, u32 zone_shift,
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 >> 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 a seq zone bitmap.
* @sdkp: target disk
* @zone_shift: logarithm base 2 of the number of blocks in a zone
* @nr_zones: number of zones to set up a seq zone bitmap for
*
* Allocate a zone bitmap and initialize it by identifying sequential zones.
*/
static unsigned long *
sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp, u32 zone_shift,
u32 nr_zones)
{
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(nr_zones, q->node);
if (!seq_zones_bitmap)
return ERR_PTR(-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,
zone_shift, seq_zones_bitmap);
}
if (lba != sdkp->capacity) {
/* Something went wrong */
ret = -EIO;
}
out:
kfree(buf);
if (ret) {
kfree(seq_zones_bitmap);
return ERR_PTR(ret);
}
return seq_zones_bitmap;
}
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, u32 zone_blocks)
{
struct request_queue *q = sdkp->disk->queue;
u32 zone_shift = ilog2(zone_blocks);
u32 nr_zones;
int ret;
/* chunk_sectors indicates the zone size */
blk_queue_chunk_sectors(q,
logical_to_sectors(sdkp->device, zone_blocks));
nr_zones = round_up(sdkp->capacity, zone_blocks) >> zone_shift;
/*
* Initialize the device request queue information if the number
* of zones changed.
*/
if (nr_zones != sdkp->nr_zones || nr_zones != q->nr_zones) {
unsigned long *seq_zones_wlock = NULL, *seq_zones_bitmap = NULL;
size_t zone_bitmap_size;
if (nr_zones) {
seq_zones_wlock = sd_zbc_alloc_zone_bitmap(nr_zones,
q->node);
if (!seq_zones_wlock) {
ret = -ENOMEM;
goto err;
}
seq_zones_bitmap = sd_zbc_setup_seq_zones_bitmap(sdkp,
zone_shift, nr_zones);
if (IS_ERR(seq_zones_bitmap)) {
ret = PTR_ERR(seq_zones_bitmap);
kfree(seq_zones_wlock);
goto err;
}
}
zone_bitmap_size = BITS_TO_LONGS(nr_zones) *
sizeof(unsigned long);
blk_mq_freeze_queue(q);
if (q->nr_zones != nr_zones) {
/* READ16/WRITE16 is mandatory for ZBC disks */
sdkp->device->use_16_for_rw = 1;
sdkp->device->use_10_for_rw = 0;
sdkp->zone_blocks = zone_blocks;
sdkp->zone_shift = zone_shift;
sdkp->nr_zones = nr_zones;
q->nr_zones = nr_zones;
swap(q->seq_zones_wlock, seq_zones_wlock);
swap(q->seq_zones_bitmap, seq_zones_bitmap);
} else if (memcmp(q->seq_zones_bitmap, seq_zones_bitmap,
zone_bitmap_size) != 0) {
memcpy(q->seq_zones_bitmap, seq_zones_bitmap,
zone_bitmap_size);
}
blk_mq_unfreeze_queue(q);
kfree(seq_zones_wlock);
kfree(seq_zones_bitmap);
}
return 0;
err:
sd_zbc_cleanup(sdkp);
return ret;
}
int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
{
int64_t zone_blocks;
struct gendisk *disk = sdkp->disk;
unsigned int nr_zones;
u32 zone_blocks;
int ret;
if (!sd_is_zoned(sdkp))
@ -675,26 +439,8 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
*/
return 0;
/* Get zoned block device characteristics */
ret = sd_zbc_read_zoned_characteristics(sdkp, buf);
if (ret)
goto err;
/*
* Check for unconstrained reads: host-managed devices with
* constrained reads (drives failing read after write pointer)
* are not supported.
*/
if (!sdkp->urswrz) {
if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp,
"constrained reads devices are not supported\n");
ret = -ENODEV;
goto err;
}
/* Check capacity */
ret = sd_zbc_check_capacity(sdkp, buf);
/* Check zoned block device characteristics (unconstrained reads) */
ret = sd_zbc_check_zoned_characteristics(sdkp, buf);
if (ret)
goto err;
@ -702,33 +448,44 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
* Check zone size: only devices with a constant zone size (except
* an eventual last runt zone) that is a power of 2 are supported.
*/
zone_blocks = sd_zbc_check_zone_size(sdkp);
ret = -EFBIG;
if (zone_blocks != (u32)zone_blocks)
goto err;
ret = zone_blocks;
if (ret < 0)
ret = sd_zbc_check_zones(sdkp, &zone_blocks);
if (ret != 0)
goto err;
/* The drive satisfies the kernel restrictions: set it up */
ret = sd_zbc_setup(sdkp, zone_blocks);
if (ret)
goto err;
blk_queue_chunk_sectors(sdkp->disk->queue,
logical_to_sectors(sdkp->device, zone_blocks));
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;
/*
* If something changed, revalidate the disk zone bitmaps once we have
* the capacity, that is on the second revalidate execution during disk
* scan and always during normal revalidate.
*/
if (sdkp->first_scan)
return 0;
if (sdkp->zone_blocks != zone_blocks ||
sdkp->nr_zones != nr_zones ||
disk->queue->nr_zones != nr_zones) {
ret = blk_revalidate_disk_zones(disk);
if (ret != 0)
goto err;
sdkp->zone_blocks = zone_blocks;
sdkp->nr_zones = nr_zones;
}
return 0;
err:
sdkp->capacity = 0;
sd_zbc_cleanup(sdkp);
return ret;
}
void sd_zbc_remove(struct scsi_disk *sdkp)
{
sd_zbc_cleanup(sdkp);
}
void sd_zbc_print_zones(struct scsi_disk *sdkp)
{
if (!sd_is_zoned(sdkp) || !sdkp->capacity)