2016-10-18 09:40:34 +03:00
/*
* SCSI Zoned Block commands
*
* Copyright ( C ) 2014 - 2015 SUSE Linux GmbH
* Written by : Hannes Reinecke < hare @ suse . de >
* Modified by : Damien Le Moal < damien . lemoal @ hgst . com >
* Modified by : Shaun Tancheff < shaun . tancheff @ seagate . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 ,
* USA .
*
*/
# include <linux/blkdev.h>
# include <asm/unaligned.h>
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include "sd.h"
/**
2017-10-10 23:54:22 +03:00
* sd_zbc_parse_report - Convert a zone descriptor to a struct blk_zone ,
* @ sdkp : The disk the report originated from
* @ buf : Address of the report zone descriptor
* @ zone : the destination zone structure
*
* All LBA sized values are converted to 512 B sectors unit .
2016-10-18 09:40:34 +03:00
*/
2017-10-10 23:54:22 +03:00
static void sd_zbc_parse_report ( struct scsi_disk * sdkp , u8 * buf ,
2016-10-18 09:40:34 +03:00
struct blk_zone * zone )
{
struct scsi_device * sdp = sdkp - > device ;
memset ( zone , 0 , sizeof ( struct blk_zone ) ) ;
zone - > type = buf [ 0 ] & 0x0f ;
zone - > cond = ( buf [ 1 ] > > 4 ) & 0xf ;
if ( buf [ 1 ] & 0x01 )
zone - > reset = 1 ;
if ( buf [ 1 ] & 0x02 )
zone - > non_seq = 1 ;
zone - > len = logical_to_sectors ( sdp , get_unaligned_be64 ( & buf [ 8 ] ) ) ;
zone - > start = logical_to_sectors ( sdp , get_unaligned_be64 ( & buf [ 16 ] ) ) ;
zone - > wp = logical_to_sectors ( sdp , get_unaligned_be64 ( & buf [ 24 ] ) ) ;
if ( zone - > type ! = ZBC_ZONE_TYPE_CONV & &
zone - > cond = = ZBC_ZONE_COND_FULL )
zone - > wp = zone - > start + zone - > len ;
}
/**
2017-10-10 23:54:22 +03:00
* sd_zbc_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
*
* For internal use during device validation .
2016-10-18 09:40:34 +03:00
*/
static int sd_zbc_report_zones ( struct scsi_disk * sdkp , unsigned char * buf ,
unsigned int buflen , sector_t lba )
{
struct scsi_device * sdp = sdkp - > device ;
const int timeout = sdp - > request_queue - > rq_timeout ;
struct scsi_sense_hdr sshdr ;
unsigned char cmd [ 16 ] ;
unsigned int rep_len ;
int result ;
memset ( cmd , 0 , 16 ) ;
cmd [ 0 ] = ZBC_IN ;
cmd [ 1 ] = ZI_REPORT_ZONES ;
put_unaligned_be64 ( lba , & cmd [ 2 ] ) ;
put_unaligned_be32 ( buflen , & cmd [ 10 ] ) ;
memset ( buf , 0 , buflen ) ;
result = scsi_execute_req ( sdp , cmd , DMA_FROM_DEVICE ,
buf , buflen , & sshdr ,
timeout , SD_MAX_RETRIES , NULL ) ;
if ( result ) {
sd_printk ( KERN_ERR , sdkp ,
" REPORT ZONES lba %llu failed with %d/%d \n " ,
( unsigned long long ) lba ,
host_byte ( result ) , driver_byte ( result ) ) ;
return - EIO ;
}
rep_len = get_unaligned_be32 ( & buf [ 0 ] ) ;
if ( rep_len < 64 ) {
sd_printk ( KERN_ERR , sdkp ,
" REPORT ZONES report invalid length %u \n " ,
rep_len ) ;
return - EIO ;
}
return 0 ;
}
2017-10-10 23:54:22 +03:00
/**
* sd_zbc_setup_report_cmnd - Prepare a REPORT ZONES scsi command
* @ cmd : The command to setup
*
* Call in sd_init_command ( ) for a REQ_OP_ZONE_REPORT request .
*/
2016-10-18 09:40:34 +03:00
int sd_zbc_setup_report_cmnd ( struct scsi_cmnd * cmd )
{
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 ) ;
if ( ! sd_is_zoned ( sdkp ) )
/* Not a zoned device */
return BLKPREP_KILL ;
ret = scsi_init_io ( cmd ) ;
if ( ret ! = BLKPREP_OK )
return ret ;
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 ;
}
2017-10-10 23:54:22 +03:00
/**
* 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 .
*/
2016-10-18 09:40:34 +03:00
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 ;
}
sg_miter_stop ( & miter ) ;
local_irq_restore ( flags ) ;
}
2017-10-10 23:54:22 +03:00
/**
* sd_zbc_zone_sectors - Get the device zone size in number of 512 B sectors .
* @ sdkp : The target disk
*/
2016-10-18 09:40:34 +03:00
static inline sector_t sd_zbc_zone_sectors ( struct scsi_disk * sdkp )
{
return logical_to_sectors ( sdkp - > device , sdkp - > zone_blocks ) ;
}
2017-10-10 23:54:22 +03:00
/**
* sd_zbc_setup_reset_cmnd - Prepare a RESET WRITE POINTER scsi command .
* @ cmd : the command to setup
*
* Called from sd_init_command ( ) for a REQ_OP_ZONE_RESET request .
*/
2016-10-18 09:40:34 +03:00
int sd_zbc_setup_reset_cmnd ( struct scsi_cmnd * cmd )
{
struct request * rq = cmd - > request ;
struct scsi_disk * sdkp = scsi_disk ( rq - > rq_disk ) ;
sector_t sector = blk_rq_pos ( rq ) ;
sector_t block = sectors_to_logical ( sdkp - > device , sector ) ;
if ( ! sd_is_zoned ( sdkp ) )
/* Not a zoned device */
return BLKPREP_KILL ;
if ( sdkp - > device - > changed )
return BLKPREP_KILL ;
if ( sector & ( sd_zbc_zone_sectors ( sdkp ) - 1 ) )
/* Unaligned request */
return BLKPREP_KILL ;
cmd - > cmd_len = 16 ;
memset ( cmd - > cmnd , 0 , cmd - > cmd_len ) ;
cmd - > cmnd [ 0 ] = ZBC_OUT ;
cmd - > cmnd [ 1 ] = ZO_RESET_WRITE_POINTER ;
put_unaligned_be64 ( block , & cmd - > cmnd [ 2 ] ) ;
rq - > timeout = SD_TIMEOUT ;
cmd - > sc_data_direction = DMA_NONE ;
cmd - > transfersize = 0 ;
cmd - > allowed = 0 ;
return BLKPREP_OK ;
}
2017-10-10 23:54:22 +03:00
/**
* sd_zbc_complete - ZBC command post processing .
* @ cmd : Completed command
* @ good_bytes : Command reply bytes
* @ sshdr : command sense header
*
* Called from sd_done ( ) . Process report zones reply and handle reset zone
* and write commands errors .
*/
void sd_zbc_complete ( struct scsi_cmnd * cmd , unsigned int good_bytes ,
2016-10-18 09:40:34 +03:00
struct scsi_sense_hdr * sshdr )
{
int result = cmd - > result ;
struct request * rq = cmd - > request ;
switch ( req_op ( rq ) ) {
2017-04-24 10:51:15 +03:00
case REQ_OP_ZONE_RESET :
if ( result & &
sshdr - > sense_key = = ILLEGAL_REQUEST & &
sshdr - > asc = = 0x24 )
/*
* INVALID FIELD IN CDB error : reset of a conventional
* zone was attempted . Nothing to worry about , so be
* quiet about the error .
*/
rq - > rq_flags | = RQF_QUIET ;
break ;
2016-10-18 09:40:34 +03:00
case REQ_OP_WRITE :
2017-04-05 20:21:02 +03:00
case REQ_OP_WRITE_ZEROES :
2016-10-18 09:40:34 +03:00
case REQ_OP_WRITE_SAME :
break ;
case REQ_OP_ZONE_REPORT :
if ( ! result )
sd_zbc_report_zones_complete ( cmd , good_bytes ) ;
break ;
}
}
/**
2018-10-12 13:08:40 +03:00
* sd_zbc_check_zoned_characteristics - Check zoned block device characteristics
2017-10-10 23:54:22 +03:00
* @ sdkp : Target disk
* @ buf : Buffer where to store the VPD page data
*
2018-10-12 13:08:40 +03:00
* Read VPD page B6 , get information and check that reads are unconstrained .
2016-10-18 09:40:34 +03:00
*/
2018-10-12 13:08:40 +03:00
static int sd_zbc_check_zoned_characteristics ( struct scsi_disk * sdkp ,
unsigned char * buf )
2016-10-18 09:40:34 +03:00
{
if ( scsi_get_vpd_page ( sdkp - > device , 0xb6 , buf , 64 ) ) {
sd_printk ( KERN_NOTICE , sdkp ,
2018-10-12 13:08:40 +03:00
" Read zoned characteristics VPD page failed \n " ) ;
2016-10-18 09:40:34 +03:00
return - ENODEV ;
}
if ( sdkp - > device - > type ! = TYPE_ZBC ) {
/* Host-aware */
sdkp - > urswrz = 1 ;
2017-10-10 23:54:25 +03:00
sdkp - > zones_optimal_open = get_unaligned_be32 ( & buf [ 8 ] ) ;
sdkp - > zones_optimal_nonseq = get_unaligned_be32 ( & buf [ 12 ] ) ;
2016-10-18 09:40:34 +03:00
sdkp - > zones_max_open = 0 ;
} else {
/* Host-managed */
sdkp - > urswrz = buf [ 4 ] & 1 ;
sdkp - > zones_optimal_open = 0 ;
sdkp - > zones_optimal_nonseq = 0 ;
2017-10-10 23:54:25 +03:00
sdkp - > zones_max_open = get_unaligned_be32 ( & buf [ 16 ] ) ;
2016-10-18 09:40:34 +03:00
}
2018-10-12 13:08:40 +03:00
/*
* 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 ;
}
2016-10-18 09:40:34 +03:00
return 0 ;
}
/**
2017-10-10 23:54:22 +03:00
* 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 .
2016-10-18 09:40:34 +03:00
*/
2017-10-10 23:54:22 +03:00
static int sd_zbc_check_capacity ( struct scsi_disk * sdkp , unsigned char * buf )
2016-10-18 09:40:34 +03:00
{
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 ;
return 0 ;
}
2017-10-10 23:54:24 +03:00
# define SD_ZBC_BUF_SIZE 131072U
2016-10-18 09:40:34 +03:00
2017-10-10 23:54:22 +03:00
/**
* sd_zbc_check_zone_size - Check the device 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 .
2018-04-17 04:04:41 +03:00
*
2018-07-03 09:23:58 +03:00
* Returns the zone size in number of blocks upon success or an error code
* upon failure .
2017-10-10 23:54:22 +03:00
*/
2018-04-17 04:04:41 +03:00
static s64 sd_zbc_check_zone_size ( struct scsi_disk * sdkp )
2016-10-18 09:40:34 +03:00
{
2018-03-02 01:19:28 +03:00
u64 zone_blocks = 0 ;
2016-10-18 09:40:34 +03:00
sector_t block = 0 ;
unsigned char * buf ;
unsigned char * rec ;
unsigned int buf_len ;
unsigned int list_length ;
2018-07-03 09:23:58 +03:00
s64 ret ;
2016-10-18 09:40:34 +03:00
u8 same ;
/* Get a buffer */
buf = kmalloc ( SD_ZBC_BUF_SIZE , GFP_KERNEL ) ;
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 ) ;
2018-03-02 01:19:28 +03:00
if ( ret )
goto out_free ;
2016-10-18 09:40:34 +03:00
same = buf [ 4 ] & 0x0f ;
if ( same > 0 ) {
rec = & buf [ 64 ] ;
zone_blocks = get_unaligned_be64 ( & rec [ 8 ] ) ;
goto out ;
}
/*
* Check the size of all zones : all zones must be of
* equal size , except the last zone which can be smaller
* than other zones .
*/
do {
/* Parse REPORT ZONES header */
list_length = get_unaligned_be32 ( & buf [ 0 ] ) + 64 ;
rec = buf + 64 ;
2017-10-10 23:54:24 +03:00
buf_len = min ( list_length , SD_ZBC_BUF_SIZE ) ;
2016-10-18 09:40:34 +03:00
/* Parse zone descriptors */
while ( rec < buf + buf_len ) {
2018-04-17 04:04:41 +03:00
u64 this_zone_blocks = get_unaligned_be64 ( & rec [ 8 ] ) ;
if ( zone_blocks = = 0 ) {
zone_blocks = this_zone_blocks ;
} else if ( this_zone_blocks ! = zone_blocks & &
( block + this_zone_blocks < sdkp - > capacity
| | this_zone_blocks > zone_blocks ) ) {
2018-05-31 11:42:40 +03:00
zone_blocks = 0 ;
2016-10-18 09:40:34 +03:00
goto out ;
}
2018-04-17 04:04:41 +03:00
block + = this_zone_blocks ;
2016-10-18 09:40:34 +03:00
rec + = 64 ;
}
if ( block < sdkp - > capacity ) {
ret = sd_zbc_report_zones ( sdkp , buf ,
SD_ZBC_BUF_SIZE , block ) ;
if ( ret )
2018-03-02 01:19:28 +03:00
goto out_free ;
2016-10-18 09:40:34 +03:00
}
} while ( block < sdkp - > capacity ) ;
out :
if ( ! zone_blocks ) {
if ( sdkp - > first_scan )
sd_printk ( KERN_NOTICE , sdkp ,
" Devices with non constant zone "
" size are not supported \n " ) ;
2018-03-02 01:19:28 +03:00
ret = - ENODEV ;
} else if ( ! is_power_of_2 ( zone_blocks ) ) {
2016-10-18 09:40:34 +03:00
if ( sdkp - > first_scan )
sd_printk ( KERN_NOTICE , sdkp ,
" Devices with non power of 2 zone "
" size are not supported \n " ) ;
2018-03-02 01:19:28 +03:00
ret = - ENODEV ;
} else if ( logical_to_sectors ( sdkp - > device , zone_blocks ) > UINT_MAX ) {
2016-10-18 09:40:34 +03:00
if ( sdkp - > first_scan )
sd_printk ( KERN_NOTICE , sdkp ,
" Zone size too large \n " ) ;
2018-03-02 01:19:28 +03:00
ret = - ENODEV ;
} else {
2018-04-17 04:04:41 +03:00
ret = zone_blocks ;
2016-10-18 09:40:34 +03:00
}
2018-03-02 01:19:28 +03:00
out_free :
kfree ( buf ) ;
2016-10-18 09:40:34 +03:00
2018-03-02 01:19:28 +03:00
return ret ;
2016-10-18 09:40:34 +03:00
}
2017-12-21 09:43:43 +03:00
/**
* sd_zbc_alloc_zone_bitmap - Allocate a zone bitmap ( one bit per zone ) .
2018-04-17 04:04:41 +03:00
* @ nr_zones : Number of zones to allocate space for .
* @ numa_node : NUMA node to allocate the memory from .
2017-12-21 09:43:43 +03:00
*/
2018-04-17 04:04:41 +03:00
static inline unsigned long *
sd_zbc_alloc_zone_bitmap ( u32 nr_zones , int numa_node )
2017-12-21 09:43:43 +03:00
{
treewide: kzalloc_node() -> kcalloc_node()
The kzalloc_node() function has a 2-factor argument form, kcalloc_node(). This
patch replaces cases of:
kzalloc_node(a * b, gfp, node)
with:
kcalloc_node(a * b, gfp, node)
as well as handling cases of:
kzalloc_node(a * b * c, gfp, node)
with:
kzalloc_node(array3_size(a, b, c), gfp, node)
as it's slightly less ugly than:
kcalloc_node(array_size(a, b), c, gfp, node)
This does, however, attempt to ignore constant size factors like:
kzalloc_node(4 * 1024, gfp, node)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc_node(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc_node(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc_node(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc_node(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc_node(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc_node(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc_node(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc_node(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc_node(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc_node(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc_node
+ kcalloc_node
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc_node
+ kcalloc_node
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc_node(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc_node(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc_node(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc_node(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc_node(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc_node(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc_node(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc_node(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc_node(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc_node(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc_node(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc_node(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc_node(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc_node(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc_node(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc_node(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc_node(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc_node(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc_node(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc_node(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc_node(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc_node(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc_node(C1 * C2 * C3, ...)
|
kzalloc_node(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc_node(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc_node(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc_node(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc_node(sizeof(THING) * C2, ...)
|
kzalloc_node(sizeof(TYPE) * C2, ...)
|
kzalloc_node(C1 * C2 * C3, ...)
|
kzalloc_node(C1 * C2, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc_node
+ kcalloc_node
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:04:20 +03:00
return kcalloc_node ( BITS_TO_LONGS ( nr_zones ) , sizeof ( unsigned long ) ,
2018-04-17 04:04:41 +03:00
GFP_KERNEL , numa_node ) ;
2017-12-21 09:43:43 +03:00
}
/**
* sd_zbc_get_seq_zones - Parse report zones reply to identify sequential zones
* @ sdkp : disk used
* @ buf : report reply buffer
2018-03-02 02:07:19 +03:00
* @ buflen : length of @ buf
2018-04-17 04:04:41 +03:00
* @ zone_shift : logarithm base 2 of the number of blocks in a zone
2018-03-02 02:07:19 +03:00
* @ seq_zones_bitmap : bitmap of sequential zones to set
2017-12-21 09:43:43 +03:00
*
* 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 ,
2018-04-17 04:04:41 +03:00
unsigned int buflen , u32 zone_shift ,
2017-12-21 09:43:43 +03:00
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 )
2018-04-17 04:04:41 +03:00
set_bit ( lba > > zone_shift , seq_zones_bitmap ) ;
2017-12-21 09:43:43 +03:00
next_lba = lba + get_unaligned_be64 ( & rec [ 8 ] ) ;
rec + = 64 ;
}
return next_lba ;
}
/**
2018-04-17 04:04:41 +03:00
* sd_zbc_setup_seq_zones_bitmap - Initialize a seq zone bitmap .
2017-12-21 09:43:43 +03:00
* @ sdkp : target disk
2018-04-17 04:04:41 +03:00
* @ 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
2017-12-21 09:43:43 +03:00
*
* Allocate a zone bitmap and initialize it by identifying sequential zones .
*/
2018-04-17 04:04:41 +03:00
static unsigned long *
sd_zbc_setup_seq_zones_bitmap ( struct scsi_disk * sdkp , u32 zone_shift ,
u32 nr_zones )
2017-12-21 09:43:43 +03:00
{
struct request_queue * q = sdkp - > disk - > queue ;
unsigned long * seq_zones_bitmap ;
sector_t lba = 0 ;
unsigned char * buf ;
int ret = - ENOMEM ;
2018-04-17 04:04:41 +03:00
seq_zones_bitmap = sd_zbc_alloc_zone_bitmap ( nr_zones , q - > node ) ;
2017-12-21 09:43:43 +03:00
if ( ! seq_zones_bitmap )
2018-04-17 04:04:41 +03:00
return ERR_PTR ( - ENOMEM ) ;
2017-12-21 09:43:43 +03:00
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 ,
2018-04-17 04:04:41 +03:00
zone_shift , seq_zones_bitmap ) ;
2017-12-21 09:43:43 +03:00
}
if ( lba ! = sdkp - > capacity ) {
/* Something went wrong */
ret = - EIO ;
}
out :
kfree ( buf ) ;
if ( ret ) {
kfree ( seq_zones_bitmap ) ;
2018-04-17 04:04:41 +03:00
return ERR_PTR ( ret ) ;
2017-12-21 09:43:43 +03:00
}
2018-04-17 04:04:41 +03:00
return seq_zones_bitmap ;
2017-12-21 09:43:43 +03:00
}
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 ;
}
2018-04-17 04:04:41 +03:00
static int sd_zbc_setup ( struct scsi_disk * sdkp , u32 zone_blocks )
2016-10-18 09:40:34 +03:00
{
2017-12-21 09:43:43 +03:00
struct request_queue * q = sdkp - > disk - > queue ;
2018-04-17 04:04:41 +03:00
u32 zone_shift = ilog2 ( zone_blocks ) ;
u32 nr_zones ;
2017-12-21 09:43:43 +03:00
int ret ;
2016-10-18 09:40:34 +03:00
/* chunk_sectors indicates the zone size */
2018-04-17 04:04:41 +03:00
blk_queue_chunk_sectors ( q ,
logical_to_sectors ( sdkp - > device , zone_blocks ) ) ;
nr_zones = round_up ( sdkp - > capacity , zone_blocks ) > > zone_shift ;
2016-10-18 09:40:34 +03:00
2017-12-21 09:43:43 +03:00
/*
* Initialize the device request queue information if the number
* of zones changed .
*/
2018-04-17 04:04:41 +03:00
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 ) {
2017-12-21 09:43:43 +03:00
ret = - ENOMEM ;
goto err ;
}
2018-04-17 04:04:41 +03:00
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 ) ;
2017-12-21 09:43:43 +03:00
goto err ;
}
}
2018-04-17 04:04:41 +03:00
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 ) ;
2016-10-18 09:40:34 +03:00
}
return 0 ;
2017-12-21 09:43:43 +03:00
err :
sd_zbc_cleanup ( sdkp ) ;
return ret ;
2016-10-18 09:40:34 +03:00
}
2017-10-10 23:54:22 +03:00
int sd_zbc_read_zones ( struct scsi_disk * sdkp , unsigned char * buf )
2016-10-18 09:40:34 +03:00
{
2018-04-17 04:04:41 +03:00
int64_t zone_blocks ;
2017-04-24 10:51:14 +03:00
int ret ;
2016-10-18 09:40:34 +03:00
if ( ! sd_is_zoned ( sdkp ) )
/*
* Device managed or normal SCSI disk ,
* no special handling required
*/
return 0 ;
2018-10-12 13:08:40 +03:00
/* Check zoned block device characteristics (unconstrained reads) */
ret = sd_zbc_check_zoned_characteristics ( sdkp , buf ) ;
2016-10-18 09:40:34 +03:00
if ( ret )
goto err ;
/* Check capacity */
ret = sd_zbc_check_capacity ( sdkp , buf ) ;
if ( ret )
goto err ;
/*
* Check zone size : only devices with a constant zone size ( except
* an eventual last runt zone ) that is a power of 2 are supported .
*/
2018-04-17 04:04:41 +03:00
zone_blocks = sd_zbc_check_zone_size ( sdkp ) ;
ret = - EFBIG ;
if ( zone_blocks ! = ( u32 ) zone_blocks )
goto err ;
ret = zone_blocks ;
if ( ret < 0 )
2016-10-18 09:40:34 +03:00
goto err ;
/* The drive satisfies the kernel restrictions: set it up */
2018-04-17 04:04:41 +03:00
ret = sd_zbc_setup ( sdkp , zone_blocks ) ;
2016-10-18 09:40:34 +03:00
if ( ret )
goto err ;
return 0 ;
err :
sdkp - > capacity = 0 ;
2017-12-21 09:43:43 +03:00
sd_zbc_cleanup ( sdkp ) ;
2016-10-18 09:40:34 +03:00
return ret ;
}
void sd_zbc_remove ( struct scsi_disk * sdkp )
{
2017-12-21 09:43:43 +03:00
sd_zbc_cleanup ( sdkp ) ;
2016-10-18 09:40:34 +03:00
}
void sd_zbc_print_zones ( struct scsi_disk * sdkp )
{
if ( ! sd_is_zoned ( sdkp ) | | ! sdkp - > capacity )
return ;
if ( sdkp - > capacity & ( sdkp - > zone_blocks - 1 ) )
sd_printk ( KERN_NOTICE , sdkp ,
" %u zones of %u logical blocks + 1 runt zone \n " ,
sdkp - > nr_zones - 1 ,
sdkp - > zone_blocks ) ;
else
sd_printk ( KERN_NOTICE , sdkp ,
" %u zones of %u logical blocks \n " ,
sdkp - > nr_zones ,
sdkp - > zone_blocks ) ;
}