diff --git a/scst/include/scst.h b/scst/include/scst.h index f7991d7a7..77ab2e0cc 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1180,8 +1180,10 @@ struct scst_tgt { /* Name of the target */ char *tgt_name; + uint16_t rel_tgt_id; + #ifdef CONFIG_SCST_PROC - /* Name on the default security group ("Default_target_name") */ + /* Name of the default security group ("Default_target_name") */ char *default_group_name; #endif diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index 636afd355..3f79e79db 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -355,4 +355,7 @@ enum scst_cdb_flags { #define SCST_SYSFS_KEY_MARK "[key]" +#define SCST_MIN_REL_TGT_ID 1 +#define SCST_MAX_REL_TGT_ID 65535 + #endif /* __SCST_CONST_H */ diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index fb7739b42..25af9e2ac 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -1881,32 +1881,96 @@ restart: return; } -struct scst_tgt *scst_alloc_tgt(struct scst_tgt_template *tgtt) +bool scst_is_relative_target_port_id_unique(uint16_t id, struct scst_tgt *t) { - struct scst_tgt *tgt; + bool res = true; + struct scst_tgt_template *tgtt; TRACE_ENTRY(); - tgt = kzalloc(sizeof(*tgt), GFP_KERNEL); - if (tgt == NULL) { + mutex_lock(&scst_mutex); + list_for_each_entry(tgtt, &scst_template_list, + scst_template_list_entry) { + struct scst_tgt *tgt; + list_for_each_entry(tgt, &tgtt->tgt_list, tgt_list_entry) { + if (tgt == t) + continue; + if (id == tgt->rel_tgt_id) { + res = false; + break; + } + } + } + mutex_unlock(&scst_mutex); + + TRACE_EXIT_RES(res); + return res; +} + +int gen_relative_target_port_id(uint16_t *id) +{ + int res = -EOVERFLOW; + static unsigned long rti = SCST_MIN_REL_TGT_ID, rti_prev; + + TRACE_ENTRY(); + + rti_prev = rti; + do { + if (scst_is_relative_target_port_id_unique(rti, NULL)) { + *id = (uint16_t)rti++; + res = 0; + goto out; + } + rti++; + if (rti > SCST_MAX_REL_TGT_ID) + rti = SCST_MIN_REL_TGT_ID; + } while (rti != rti_prev); + + PRINT_ERROR("%s", "Unable to create unique relative target port id"); + +out: + TRACE_EXIT_RES(res); + return res; +} + +int scst_alloc_tgt(struct scst_tgt_template *tgtt, struct scst_tgt **tgt) +{ + struct scst_tgt *t; + int res = 0; + + TRACE_ENTRY(); + + t = kzalloc(sizeof(*t), GFP_KERNEL); + if (t == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of tgt failed"); + res = -ENOMEM; goto out; } - INIT_LIST_HEAD(&tgt->sess_list); - init_waitqueue_head(&tgt->unreg_waitQ); - tgt->tgtt = tgtt; - tgt->sg_tablesize = tgtt->sg_tablesize; - spin_lock_init(&tgt->tgt_lock); - INIT_LIST_HEAD(&tgt->retry_cmd_list); - atomic_set(&tgt->finished_cmds, 0); - init_timer(&tgt->retry_timer); - tgt->retry_timer.data = (unsigned long)tgt; - tgt->retry_timer.function = scst_tgt_retry_timer_fn; + INIT_LIST_HEAD(&t->sess_list); + init_waitqueue_head(&t->unreg_waitQ); + t->tgtt = tgtt; + t->sg_tablesize = tgtt->sg_tablesize; + spin_lock_init(&t->tgt_lock); + INIT_LIST_HEAD(&t->retry_cmd_list); + atomic_set(&t->finished_cmds, 0); + init_timer(&t->retry_timer); + t->retry_timer.data = (unsigned long)t; + t->retry_timer.function = scst_tgt_retry_timer_fn; + +#ifdef CONFIG_SCST_PROC + res = gen_relative_target_port_id(&t->rel_tgt_id); + if (res != 0) { + scst_free_tgt(t); + goto out; + } +#endif + + *tgt = t; out: - TRACE_EXIT_HRES((unsigned long)tgt); - return tgt; + TRACE_EXIT_HRES(res); + return res; } void scst_free_tgt(struct scst_tgt *tgt) diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index e5ad825c9..9f2295c0f 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -361,11 +361,9 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt, TRACE_ENTRY(); - tgt = scst_alloc_tgt(vtt); - if (tgt == NULL) { - rc = -ENOMEM; + rc = scst_alloc_tgt(vtt, &tgt); + if (rc != 0) goto out_err; - } rc = scst_suspend_activity(true); if (rc != 0) @@ -449,8 +447,13 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt, mutex_unlock(&scst_mutex); scst_resume_activity(); +#ifdef CONFIG_SCST_PROC + PRINT_INFO("Target %s (rel ID %d) for template %s registered successfully", + tgt->tgt_name, tgt->rel_tgt_id, vtt->name); +#else PRINT_INFO("Target %s for template %s registered successfully", tgt->tgt_name, vtt->name); +#endif TRACE_DBG("tgt %p", tgt); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index c5e7ecece..7351587ba 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -296,7 +296,7 @@ int scst_queue_retry_cmd(struct scst_cmd *cmd, int finished_cmds); static inline void scst_tgtt_cleanup(struct scst_tgt_template *tgtt) { } static inline void scst_devt_cleanup(struct scst_dev_type *devt) { } -struct scst_tgt *scst_alloc_tgt(struct scst_tgt_template *tgtt); +int scst_alloc_tgt(struct scst_tgt_template *tgtt, struct scst_tgt **tgt); void scst_free_tgt(struct scst_tgt *tgt); int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev); @@ -735,6 +735,9 @@ static inline int scst_sn_before(__u32 seq1, __u32 seq2) return (__s32)(seq1-seq2) < 0; } +bool scst_is_relative_target_port_id_unique(uint16_t id, struct scst_tgt *t); +int gen_relative_target_port_id(uint16_t *id); + #ifdef CONFIG_SCST_MEASURE_LATENCY void scst_set_start_time(struct scst_cmd *cmd); diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index f892dfa49..f03544053 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -112,6 +112,12 @@ static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj, static ssize_t scst_ini_group_mgmt_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t scst_rel_tgt_id_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf); +static ssize_t scst_rel_tgt_id_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); static ssize_t scst_acg_luns_mgmt_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); @@ -526,6 +532,10 @@ static struct kobj_attribute scst_ini_group_mgmt = __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_ini_group_mgmt_show, scst_ini_group_mgmt_store); +static struct kobj_attribute scst_rel_tgt_id = + __ATTR(rel_tgt_id, S_IRUGO | S_IWUSR, scst_rel_tgt_id_show, + scst_rel_tgt_id_store); + static ssize_t scst_tgt_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -558,6 +568,23 @@ static ssize_t scst_tgt_enable_store(struct kobject *kobj, tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + if (buf[0] == '1') { + if (tgt->rel_tgt_id == 0) { + res = gen_relative_target_port_id(&tgt->rel_tgt_id); + if (res) + goto out; + PRINT_INFO("Using autogenerated rel ID %d for target " + "%s", tgt->rel_tgt_id, tgt->tgt_name); + } else + if (!scst_is_relative_target_port_id_unique( + tgt->rel_tgt_id, tgt)) { + PRINT_ERROR("Relative port id %d is not unique", + tgt->rel_tgt_id); + res = -EBADSLT; + goto out; + } + } + res = tgt->tgtt->enable_target(tgt, buf, count); if (res == 0) res = count; @@ -638,13 +665,21 @@ int scst_create_tgt_sysfs(struct scst_tgt *tgt) } retval = sysfs_create_file(tgt->tgt_ini_grp_kobj, - &scst_ini_group_mgmt.attr); + &scst_ini_group_mgmt.attr); if (retval != 0) { PRINT_ERROR("Can't add tgt attr %s for tgt %s", scst_ini_group_mgmt.attr.name, tgt->tgt_name); goto out; } + retval = sysfs_create_file(&tgt->tgt_kobj, + &scst_rel_tgt_id.attr); + if (retval != 0) { + PRINT_ERROR("Can't add attribute %s for tgt %s", + scst_rel_tgt_id.attr.name, tgt->tgt_name); + goto out; + } + pattr = tgt->tgtt->tgt_attrs; if (pattr != NULL) { while (*pattr != NULL) { @@ -1797,6 +1832,80 @@ out_free_acg: #undef SCST_LUN_ACTION_DEL } +static ssize_t scst_rel_tgt_id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_tgt *tgt; + int res; + + TRACE_ENTRY(); + + tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + + res = sprintf(buf, "%d\n%s", tgt->rel_tgt_id, + (tgt->rel_tgt_id != 0) ? SCST_SYSFS_KEY_MARK "\n" : ""); + + TRACE_EXIT_RES(res); + return res; +} + +static ssize_t scst_rel_tgt_id_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res = 0; + struct scst_tgt *tgt; + unsigned long rel_tgt_id; + + TRACE_ENTRY(); + + if (buf == NULL) + goto out_err; + + tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + + res = strict_strtoul(buf, 0, &rel_tgt_id); + if (res != 0) + goto out_err; + + TRACE_DBG("Try to set relative target port id %d", + (uint16_t)rel_tgt_id); + + if (rel_tgt_id < SCST_MIN_REL_TGT_ID || + rel_tgt_id > SCST_MAX_REL_TGT_ID) { + if ((rel_tgt_id == 0) && !tgt->tgtt->is_target_enabled(tgt)) + goto set; + + PRINT_ERROR("Invalid relative port id %d", + (uint16_t)rel_tgt_id); + res = -EINVAL; + goto out; + } + + if (tgt->tgtt->is_target_enabled(tgt) && + rel_tgt_id != tgt->rel_tgt_id) { + if (!scst_is_relative_target_port_id_unique(rel_tgt_id, tgt)) { + PRINT_ERROR("Relative port id %d is not unique", + (uint16_t)rel_tgt_id); + res = -EBADSLT; + goto out; + } + } + +set: + tgt->rel_tgt_id = (uint16_t)rel_tgt_id; + + res = count; + +out: + TRACE_EXIT_RES(res); + return res; + +out_err: + PRINT_ERROR("%s: Requested action not understood: %s", __func__, buf); + res = -EINVAL; + goto out; +} + int scst_create_acn_sysfs(struct scst_acg *acg, struct scst_acn *acn) { int retval = 0;