Added support for user-defined block size (actually "sector size"). The rationale is for using with devices (notably SSDs) that allow formatting with sector size different from 512B. If such device is formatted to a greater value, but tgt reports its sector size to be 512B, all commands referencing device sectors and/or extents will address wrong locations, some of which will be even out of the device's capacity. This patch follows the patch posted here: http://lists.wpkg.org/pipermail/stgt/2009-December/003469.html and elaborates the suggested functionality a bit further. The default block size is maintained by sbc (block devices). It has its own default value 512B. This default may be overridden by using the following extra param in tgt command line: --sbc blocksize=4096 (sizes 512,1024..8096 are supported). After this all block devices will report the passed block sz value during scsi inquiries. Block size can be set for individual luns as well using --params blocksize=4096,... among the parameters of new logical unit through tgtadm. This may be used in scripts as follows: --params blocksize=`blockdev --getss /dev/sdd` In this case lun specific setting overrides sbc default. Tha actual per lun is displayed through -m target -o show. Signed-off-by: Alexander Nezhinsky <alexandern@xxxxxxxxxxxx> --- usr/sbc.c | 51 +++++++++++++++++++++++++++++++++++++++++++-------- usr/target.c | 35 +++++++++++++++++++++++++++++++---- usr/tgtd.h | 1 + usr/util.c | 19 +++++++++++++++++++ usr/util.h | 1 + 5 files changed, 95 insertions(+), 12 deletions(-) diff --git a/usr/sbc.c b/usr/sbc.c index 1f0a6ff..88cd893 100644 --- a/usr/sbc.c +++ b/usr/sbc.c @@ -41,7 +41,9 @@ #include "spc.h" #include "tgtadm_error.h" -#define BLK_SHIFT 9 +#define DEFAULT_BLK_SHIFT 9 + +static unsigned int blk_shift = DEFAULT_BLK_SHIFT; static int sbc_mode_page_update(struct scsi_cmd *cmd, uint8_t *data, int *changed) { @@ -123,7 +125,7 @@ static int sbc_rw(int host_no, struct scsi_cmd *cmd) cmd->scsi_cmd_done = target_cmd_io_done; - cmd->offset = (scsi_rw_offset(cmd->scb) << BLK_SHIFT); + cmd->offset = (scsi_rw_offset(cmd->scb) << cmd->dev->blk_shift); ret = cmd->dev->bst->bs_cmd_submit(cmd); if (ret) { key = HARDWARE_ERROR; @@ -163,6 +165,7 @@ static int sbc_release(int host_no, struct scsi_cmd *cmd) static int sbc_read_capacity(int host_no, struct scsi_cmd *cmd) { uint32_t *data; + unsigned int bshift; uint64_t size; uint8_t *scb = cmd->scb; unsigned char key = ILLEGAL_REQUEST; @@ -177,11 +180,12 @@ static int sbc_read_capacity(int host_no, struct scsi_cmd *cmd) goto overflow; data = scsi_get_in_buffer(cmd); - size = cmd->dev->size >> BLK_SHIFT; + bshift = cmd->dev->blk_shift; + size = cmd->dev->size >> bshift; data[0] = (size >> 32) ? __cpu_to_be32(0xffffffff) : __cpu_to_be32(size - 1); - data[1] = __cpu_to_be32(1U << BLK_SHIFT); + data[1] = __cpu_to_be32(1U << bshift); overflow: scsi_set_in_resid_by_actual(cmd, 8); @@ -200,6 +204,7 @@ static int sbc_verify(int host_no, struct scsi_cmd *cmd) static int sbc_service_action(int host_no, struct scsi_cmd *cmd) { uint32_t *data; + unsigned int bshift; uint64_t size; int len = 32; @@ -214,10 +219,11 @@ static int sbc_service_action(int host_no, struct scsi_cmd *cmd) data = scsi_get_in_buffer(cmd); memset(data, 0, len); - size = cmd->dev->size >> BLK_SHIFT; + bshift = cmd->dev->blk_shift; + size = cmd->dev->size >> bshift; *((uint64_t *)(data)) = __cpu_to_be64(size - 1); - data[2] = __cpu_to_be32(1UL << BLK_SHIFT); + data[2] = __cpu_to_be32(1UL << bshift); overflow: scsi_set_in_resid_by_actual(cmd, len); @@ -276,11 +282,14 @@ static int sbc_lu_init(struct scsi_lu *lu) lu->attrs.version_desc[2] = 0x0300; /* SPC-3 */ data = lu->mode_block_descriptor; - size = lu->size >> BLK_SHIFT; + + if (!lu->blk_shift) + lu->blk_shift = blk_shift; /* if unset, use default shift */ + size = lu->size >> lu->blk_shift; /* calculate size in blocks */ *(uint32_t *)(data) = (size >> 32) ? __cpu_to_be32(0xffffffff) : __cpu_to_be32(size); - *(uint32_t *)(data + 4) = __cpu_to_be32(1 << BLK_SHIFT); + *(uint32_t *)(data + 4) = __cpu_to_be32(1 << lu->blk_shift); /* Vendor uniq - However most apps seem to call for mode page 0*/ add_mode_page(lu, "0:0:0"); @@ -472,7 +481,33 @@ static struct device_type_template sbc_template = { } }; +static int sbc_param_parser(char *p) +{ + while (*p) { + if (!strncmp(p, "blocksize=", 10)) { + unsigned int blocksize; + unsigned int shift; + + blocksize = atoi(p + 10); + + shift = get_blk_shift(blocksize); + if (shift > 0) + blk_shift = shift; /* set default shift */ + else + eprintf("%u is invalid block size\n", blocksize); + } + + p += strcspn(p, ","); + if (*p == ',') + ++p; + } + + return 0; +} + __attribute__((constructor)) static void sbc_init(void) { device_type_register(&sbc_template); + + setup_param("sbc", sbc_param_parser); } diff --git a/usr/target.c b/usr/target.c index 79798ad..ebfeb7d 100644 --- a/usr/target.c +++ b/usr/target.c @@ -445,13 +445,14 @@ __device_lookup(int tid, uint64_t lun, struct target **t) } enum { - Opt_path, Opt_bstype, Opt_bsoflags, Opt_err, + Opt_path, Opt_bstype, Opt_bsoflags, Opt_blocksize, Opt_err, }; static match_table_t device_tokens = { {Opt_path, "path=%s"}, {Opt_bstype, "bstype=%s"}, {Opt_bsoflags, "bsoflags=%s"}, + {Opt_blocksize, "blocksize=%s"}, {Opt_err, NULL}, }; @@ -460,7 +461,8 @@ static void __cmd_done(struct target *, struct scsi_cmd *); int tgt_device_create(int tid, int dev_type, uint64_t lun, char *params, int backing) { - char *p, *path = NULL, *bstype = NULL, *bsoflags = NULL; + char *p, *path = NULL, *bstype = NULL; + char *bsoflags = NULL, *blocksize = NULL; int ret = 0, lu_bsoflags = 0; struct target *target; struct scsi_lu *lu, *pos; @@ -486,6 +488,9 @@ int tgt_device_create(int tid, int dev_type, uint64_t lun, char *params, break; case Opt_bsoflags: bsoflags = match_strdup(&args[0]); + case Opt_blocksize: + blocksize = match_strdup(&args[0]); + break; default: break; } @@ -565,7 +570,26 @@ int tgt_device_create(int tid, int dev_type, uint64_t lun, char *params, lu->cmd_perform = &target_cmd_perform; lu->cmd_done = &__cmd_done; - if (lu->dev_type_template.lu_init) { + lu->blk_shift = 0; + if (blocksize) { + unsigned int bsize; + unsigned int bshift; + + dprintf("blocksize=%s\n", blocksize); + bsize = strtoul(blocksize, NULL, 0); + + bshift = get_blk_shift(bsize); + if (bshift > 0) + lu->blk_shift = bshift; + else { + if (bsize > 0) + eprintf("%u is invalid block size\n", bsize); + else + eprintf("%s is invalid block size\n", blocksize); + } + } + + if (lu->dev_type_template.lu_init) { ret = lu->dev_type_template.lu_init(lu); if (ret) goto fail_lu_init; @@ -624,6 +648,8 @@ int tgt_device_create(int tid, int dev_type, uint64_t lun, char *params, out: if (bstype) free(bstype); + if (blocksize) + free(blocksize); if (path) free(path); if (bsoflags) @@ -1746,7 +1772,7 @@ int tgt_target_show_all(char *buf, int rest) _TAB3 "Type: %s\n" _TAB3 "SCSI ID: %s\n" _TAB3 "SCSI SN: %s\n" - _TAB3 "Size: %s\n" + _TAB3 "Size: %s, Block size: %d\n" _TAB3 "Online: %s\n" _TAB3 "Removable media: %s\n" _TAB3 "Readonly: %s\n" @@ -1758,6 +1784,7 @@ int tgt_target_show_all(char *buf, int rest) lu->attrs.scsi_id, lu->attrs.scsi_sn, print_disksize(lu->size), + 1U << lu->blk_shift, lu->attrs.online ? "Yes" : "No", lu->attrs.removable ? "Yes" : "No", lu->attrs.readonly ? "Yes" : "No", diff --git a/usr/tgtd.h b/usr/tgtd.h index 3a328e6..37943d2 100644 --- a/usr/tgtd.h +++ b/usr/tgtd.h @@ -154,6 +154,7 @@ struct scsi_lu { uint64_t lun; char *path; int bsoflags; + unsigned int blk_shift; /* the list of devices belonging to a target */ struct list_head device_siblings; diff --git a/usr/util.c b/usr/util.c index fdd1805..c78a999 100644 --- a/usr/util.c +++ b/usr/util.c @@ -175,3 +175,22 @@ char *open_flags_to_str(char *dest, int flags) } return dest; } + +int get_blk_shift(unsigned int size) +{ + int shift = 0; + + if (!size) + return -1; + + /* find the first non-zero bit */ + while ((size & (1 << shift)) == 0) + shift++; + + /* if more non-zero bits, then size is not a power of 2 */ + if (size > (1 << shift)) + return -1; + + return shift; +} + diff --git a/usr/util.h b/usr/util.h index 24a5eb7..9530d2a 100644 --- a/usr/util.h +++ b/usr/util.h @@ -54,6 +54,7 @@ #define max_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) +extern int get_blk_shift(unsigned int size); extern int chrdev_open(char *modname, char *devpath, uint8_t minor, int *fd); extern int backed_file_open(char *path, int oflag, uint64_t *size); extern int set_non_blocking(int fd); -- 1.7.3 -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html