sd: Implement support for ZBC devices
Implement ZBC support functions to setup zoned disks, both host-managed and host-aware models. Only zoned disks that satisfy the following conditions are supported: 1) All zones are the same size, with the exception of an eventual last smaller runt zone. 2) For host-managed disks, reads are unrestricted (reads are not failed due to zone or write pointer alignement constraints). Zoned disks that do not satisfy these 2 conditions are setup with a capacity of 0 to prevent their use. The function sd_zbc_read_zones, called from sd_revalidate_disk, checks that the device satisfies the above two constraints. This function may also change the disk capacity previously set by sd_read_capacity for devices reporting only the capacity of conventional zones at the beginning of the LBA range (i.e. devices reporting rc_basis set to 0). The capacity message output was moved out of sd_read_capacity into a new function sd_print_capacity to include this eventual capacity change by sd_zbc_read_zones. This new function also includes a call to sd_zbc_print_zones to display the number of zones and zone size of the device. Signed-off-by: Hannes Reinecke <hare@suse.de> [Damien: * Removed zone cache support * Removed mapping of discard to reset write pointer command * Modified sd_zbc_read_zones to include checks that the device satisfies the kernel constraints * Implemeted REPORT ZONES setup and post-processing based on code from Shaun Tancheff <shaun.tancheff@seagate.com> * Removed confusing use of 512B sector units in functions interface] Signed-off-by: Damien Le Moal <damien.lemoal@hgst.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Shaun Tancheff <shaun.tancheff@seagate.com> Tested-by: Shaun Tancheff <shaun.tancheff@seagate.com> Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:

committed by
Jens Axboe

parent
3ed05a987e
commit
89d9475610
@@ -64,6 +64,15 @@ struct scsi_disk {
|
||||
struct scsi_device *device;
|
||||
struct device dev;
|
||||
struct gendisk *disk;
|
||||
#ifdef CONFIG_BLK_DEV_ZONED
|
||||
unsigned int nr_zones;
|
||||
unsigned int zone_blocks;
|
||||
unsigned int zone_shift;
|
||||
unsigned long *zones_wlock;
|
||||
unsigned int zones_optimal_open;
|
||||
unsigned int zones_optimal_nonseq;
|
||||
unsigned int zones_max_open;
|
||||
#endif
|
||||
atomic_t openers;
|
||||
sector_t capacity; /* size in logical blocks */
|
||||
u32 max_xfer_blocks;
|
||||
@@ -94,6 +103,9 @@ struct scsi_disk {
|
||||
unsigned lbpvpd : 1;
|
||||
unsigned ws10 : 1;
|
||||
unsigned ws16 : 1;
|
||||
unsigned rc_basis: 2;
|
||||
unsigned zoned: 2;
|
||||
unsigned urswrz : 1;
|
||||
};
|
||||
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
|
||||
|
||||
@@ -156,6 +168,11 @@ static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t b
|
||||
return blocks * sdev->sector_size;
|
||||
}
|
||||
|
||||
static inline sector_t sectors_to_logical(struct scsi_device *sdev, sector_t sector)
|
||||
{
|
||||
return sector >> (ilog2(sdev->sector_size) - 9);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the DIX operation based on whether the command is read or
|
||||
* write and whether dix and dif are enabled.
|
||||
@@ -239,4 +256,57 @@ static inline void sd_dif_complete(struct scsi_cmnd *cmd, unsigned int a)
|
||||
|
||||
#endif /* CONFIG_BLK_DEV_INTEGRITY */
|
||||
|
||||
static inline int sd_is_zoned(struct scsi_disk *sdkp)
|
||||
{
|
||||
return sdkp->zoned == 1 || sdkp->device->type == TYPE_ZBC;
|
||||
}
|
||||
|
||||
#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_write_cmnd(struct scsi_cmnd *cmd);
|
||||
extern void sd_zbc_cancel_write_cmnd(struct scsi_cmnd *cmd);
|
||||
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);
|
||||
|
||||
#else /* CONFIG_BLK_DEV_ZONED */
|
||||
|
||||
static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
|
||||
unsigned char *buf)
|
||||
{
|
||||
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_write_cmnd(struct scsi_cmnd *cmd)
|
||||
{
|
||||
/* Let the drive fail requests */
|
||||
return BLKPREP_OK;
|
||||
}
|
||||
|
||||
static inline void sd_zbc_cancel_write_cmnd(struct scsi_cmnd *cmd) {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void sd_zbc_complete(struct scsi_cmnd *cmd,
|
||||
unsigned int good_bytes,
|
||||
struct scsi_sense_hdr *sshdr) {}
|
||||
|
||||
#endif /* CONFIG_BLK_DEV_ZONED */
|
||||
|
||||
#endif /* _SCSI_DISK_H */
|
||||
|
Reference in New Issue
Block a user