diff --git a/scst/README b/scst/README index 71934da85..17866b98f 100644 --- a/scst/README +++ b/scst/README @@ -602,6 +602,12 @@ following entries: - targets - this is a root subdirectory for all SCST targets + - setup_id - allows to read and write SCST setup ID. This ID can be + used in cases, when the same SCST configuration should be installed + on several targets, but exported from those targets devices should + have different IDs and SNs. For instance, VDISK dev handler uses this + ID to generate T10 vendor specific identifier and SN of the devices. + - threads - allows to read and set number of global SCST I/O threads. Those threads used with async. dev handlers, for instance, vdisk BLOCKIO or NULLIO. diff --git a/scst/README_in-tree b/scst/README_in-tree index 46d32ec1e..86d370229 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -525,6 +525,12 @@ following entries: - targets - this is a root subdirectory for all SCST targets + - setup_id - allows to read and write SCST setup ID. This ID can be + used in cases, when the same SCST configuration should be installed + on several targets, but exported from those targets devices should + have different IDs and SNs. For instance, VDISK dev handler uses this + ID to generate T10 vendor specific identifier and SN of the devices. + - threads - allows to read and set number of global SCST I/O threads. Those threads used with async. dev handlers, for instance, vdisk BLOCKIO or NULLIO. diff --git a/scst/include/scst.h b/scst/include/scst.h index 4cb0b7855..115910d4c 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -3690,6 +3690,12 @@ struct scst_sysfs_user_info *scst_sysfs_user_get_info(uint32_t cookie); int scst_wait_info_completion(struct scst_sysfs_user_info *info, unsigned long timeout); +/* + * This function returns SCST setup ID. This ID can be used with multiple + * setups with the same configuration. + */ +unsigned int scst_get_setup_id(void); + #endif /* CONFIG_SCST_PROC */ /* diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 3f9dfc8d0..444c35406 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -560,6 +560,7 @@ static struct scst_dev_type vcdrom_devtype = { static struct scst_vdisk_thr nullio_thr_data; #ifdef CONFIG_SCST_PROC + static char *vdisk_proc_help_string = "echo \"open|close|resync_size NAME [FILE_NAME [BLOCK_SIZE] " "[WRITE_THROUGH READ_ONLY O_DIRECT NULLIO NV_CACHE BLOCKIO]]\" " @@ -570,13 +571,14 @@ static char *vdisk_proc_help_string = static char *vcdrom_proc_help_string = "echo \"open|change|close NAME [FILE_NAME]\" " ">/proc/scsi_tgt/vcdrom/vcdrom\n"; -#endif static int scst_vdisk_ID; module_param_named(scst_vdisk_ID, scst_vdisk_ID, int, S_IRUGO); MODULE_PARM_DESC(scst_vdisk_ID, "SCST virtual disk subsystem ID"); +#endif /* CONFIG_SCST_PROC */ + static const char *vdev_get_filename(const struct scst_vdisk_dev *virt_dev) { if (virt_dev->filename != NULL) @@ -1256,7 +1258,11 @@ static uint64_t vdisk_gen_dev_id_num(const char *virt_dev_name) dev_id_num ^= ((rv << i) | (rv >> (32 - i))); } +#ifdef CONFIG_SCST_PROC return ((uint64_t)scst_vdisk_ID << 32) | dev_id_num; +#else + return ((uint64_t)scst_get_setup_id() << 32) | dev_id_num; +#endif } static void vdisk_exec_inquiry(struct scst_cmd *cmd) @@ -2925,9 +2931,10 @@ out: return res; } -static struct scst_vdisk_dev *vdev_create(struct scst_dev_type *devt, - const char *name) +static int vdev_create(struct scst_dev_type *devt, + const char *name, struct scst_vdisk_dev **res_virt_dev) { + int res = 0; struct scst_vdisk_dev *virt_dev; uint64_t dev_id_num; int dev_id_len; @@ -2938,6 +2945,7 @@ static struct scst_vdisk_dev *vdev_create(struct scst_dev_type *devt, if (virt_dev == NULL) { PRINT_ERROR("Allocation of virtual device %s failed", devt->name); + res = -ENOMEM; goto out; } @@ -2951,7 +2959,13 @@ static struct scst_vdisk_dev *vdev_create(struct scst_dev_type *devt, virt_dev->block_size = DEF_DISK_BLOCKSIZE; virt_dev->block_shift = DEF_DISK_BLOCKSIZE_SHIFT; - strncpy(virt_dev->name, name, sizeof(virt_dev->name)); + if (strlen(name) >= sizeof(virt_dev->name)) { + PRINT_ERROR("Name %s is too long (max allowed %d)", name, + sizeof(virt_dev->name)-1); + res = -EINVAL; + goto out_free; + } + strcpy(virt_dev->name, name); dev_id_num = vdisk_gen_dev_id_num(virt_dev->name); dev_id_len = scnprintf(dev_id_str, sizeof(dev_id_str), "%llx", @@ -2966,8 +2980,14 @@ static struct scst_vdisk_dev *vdev_create(struct scst_dev_type *devt, scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx", dev_id_num); TRACE_DBG("usn %s", virt_dev->usn); + *res_virt_dev = virt_dev; + out: - return virt_dev; + return res; + +out_free: + kfree(virt_dev); + goto out; } static void vdev_destroy(struct scst_vdisk_dev *virt_dev) @@ -3008,11 +3028,9 @@ static int vdev_fileio_add_device(const char *device_name, char *params) TRACE_ENTRY(); - virt_dev = vdev_create(&vdisk_file_devtype, device_name); - if (virt_dev == NULL) { - res = -ENOMEM; + res = vdev_create(&vdisk_file_devtype, device_name, &virt_dev); + if (res != 0) goto out; - } virt_dev->wt_flag = DEF_WRITE_THROUGH; virt_dev->nv_cache = DEF_NV_CACHE; @@ -3160,11 +3178,9 @@ static int vdev_blockio_add_device(const char *device_name, char *params) TRACE_ENTRY(); - virt_dev = vdev_create(&vdisk_blk_devtype, device_name); - if (virt_dev == NULL) { - res = -ENOMEM; + res = vdev_create(&vdisk_blk_devtype, device_name, &virt_dev); + if (res != 0) goto out; - } virt_dev->blockio = 1; @@ -3288,11 +3304,9 @@ static int vdev_nullio_add_device(const char *device_name, char *params) TRACE_ENTRY(); - virt_dev = vdev_create(&vdisk_null_devtype, device_name); - if (virt_dev == NULL) { - res = -ENOMEM; + res = vdev_create(&vdisk_null_devtype, device_name, &virt_dev); + if (res != 0) goto out; - } virt_dev->nullio = 1; @@ -3511,11 +3525,9 @@ static int __vcdrom_add_device(const char *device_name, char *params) goto out; } - virt_dev = vdev_create(&vcdrom_devtype, device_name); - if (virt_dev == NULL) { - res = -ENOMEM; + res = vdev_create(&vcdrom_devtype, device_name, &virt_dev); + if (res != 0) goto out; - } virt_dev->rd_only = 1; virt_dev->removable = 1; @@ -4227,12 +4239,9 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset, goto out_up; } - /* It's going to be removed code, anyway */ - virt_dev = vdev_create(dev_type, name); - if (virt_dev == NULL) { - res = -ENOMEM; + res = vdev_create(dev_type, name, &virt_dev); + if (res != 0) goto out_up; - } virt_dev->wt_flag = DEF_WRITE_THROUGH; virt_dev->nv_cache = DEF_NV_CACHE; @@ -4508,13 +4517,10 @@ static int vcdrom_open(char *p, char *name) } else cdrom_empty = 0; - virt_dev = vdev_create(&vcdrom_devtype, name); - if (virt_dev == NULL) { - TRACE(TRACE_OUT_OF_MEM, "%s", - "Allocation of virt_dev failed"); - res = -ENOMEM; + res = vdev_create(&vcdrom_devtype, name, &virt_dev); + if (res != 0) goto out; - } + virt_dev->cdrom_empty = cdrom_empty; virt_dev->rd_only = 1; virt_dev->removable = 1; diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 3c1f118fb..5d5d68889 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -105,6 +105,8 @@ struct kmem_cache *scst_acgd_cachep; #ifdef CONFIG_SCST_PROC struct list_head scst_acg_list; struct scst_acg *scst_default_acg; +#else +unsigned int scst_setup_id; #endif spinlock_t scst_init_lock; @@ -1778,6 +1780,14 @@ void scst_put(void) } EXPORT_SYMBOL(scst_put); +#ifndef CONFIG_SCST_PROC +unsigned int scst_get_setup_id(void) +{ + return scst_setup_id; +} +EXPORT_SYMBOL(scst_get_setup_id); +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) static int scst_add(struct class_device *cdev, struct class_interface *intf) #else diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index f82fb15ad..8c7fa1370 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -152,6 +152,8 @@ extern wait_queue_head_t scst_dev_cmd_waitQ; #ifdef CONFIG_SCST_PROC extern struct list_head scst_acg_list; extern struct scst_acg *scst_default_acg; +#else +extern unsigned int scst_setup_id; #endif extern spinlock_t scst_init_lock; @@ -423,7 +425,7 @@ void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd); void scst_done_cmd_mgmt(struct scst_cmd *cmd); #ifdef CONFIG_SCST_PROC -/* /proc support */ + int scst_proc_init_module(void); void scst_proc_cleanup_module(void); int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt); @@ -432,10 +434,7 @@ int scst_build_proc_target_entries(struct scst_tgt *vtt); void scst_cleanup_proc_target_entries(struct scst_tgt *vtt); int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type); void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type); -#endif -/* sysfs support */ -#ifdef CONFIG_SCST_PROC static inline int scst_sysfs_init(void) { return 0; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 9ed692b69..e2a5caf7a 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -2396,8 +2396,8 @@ static ssize_t scst_threads_show(struct kobject *kobj, static ssize_t scst_threads_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { - int res = count; - int oldtn, newtn, delta; + int res; + long oldtn, newtn, delta; TRACE_ENTRY(); @@ -2407,20 +2407,22 @@ static ssize_t scst_threads_store(struct kobject *kobj, } oldtn = scst_nr_global_threads; - sscanf(buf, "%du", &newtn); - if (newtn <= 0) { - PRINT_ERROR("Illegal threads num value %d", newtn); - res = -EINVAL; + res = strict_strtoul(buf, 0, &newtn); + if (res != 0) { + PRINT_ERROR("strict_strtoul() for %s failed: %d ", buf, res); goto out_up; } + delta = newtn - oldtn; if (delta < 0) __scst_del_global_threads(-delta); else __scst_add_global_threads(delta); - PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn); + PRINT_INFO("Changed cmd threads num: old %ld, new %ld", oldtn, newtn); + + res = count; out_up: mutex_unlock(&scst_global_threads_mutex); @@ -2430,6 +2432,44 @@ out: return res; } +static ssize_t scst_setup_id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int count; + + TRACE_ENTRY(); + + count = sprintf(buf, "%x%s\n", scst_setup_id, + (scst_setup_id == 0) ? "" : SCST_SYSFS_KEY_MARK "\n"); + + TRACE_EXIT(); + return count; +} + +static ssize_t scst_setup_id_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res; + unsigned long val; + + TRACE_ENTRY(); + + res = strict_strtoul(buf, 0, &val); + if (res != 0) { + PRINT_ERROR("strict_strtoul() for %s failed: %d ", buf, res); + goto out; + } + + scst_setup_id = val; + PRINT_INFO("Changed scst_setup_id to %x", scst_setup_id); + + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) static void scst_read_trace_tlb(const struct scst_trace_log *tbl, char *buf, @@ -2725,6 +2765,10 @@ static struct kobj_attribute scst_threads_attr = __ATTR(threads, S_IRUGO | S_IWUSR, scst_threads_show, scst_threads_store); +static struct kobj_attribute scst_setup_id_attr = + __ATTR(setup_id, S_IRUGO | S_IWUSR, scst_setup_id_show, + scst_setup_id_store); + #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) static struct kobj_attribute scst_trace_level_attr = __ATTR(trace_level, S_IRUGO | S_IWUSR, scst_main_trace_level_show, @@ -2736,6 +2780,7 @@ static struct kobj_attribute scst_version_attr = static struct attribute *scst_sysfs_root_default_attrs[] = { &scst_threads_attr.attr, + &scst_setup_id_attr.attr, #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) &scst_trace_level_attr.attr, #endif