diff --git a/scst/include/scst.h b/scst/include/scst.h index 7dc48ff3e..5588de7d2 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -2076,6 +2076,8 @@ struct scst_acg { struct kobject *luns_kobj; struct kobject *initiators_kobj; + + unsigned int addr_method; }; /* diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index d5976ce10..337972f0e 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -1107,7 +1107,7 @@ static struct scst_aen *scst_alloc_aen(struct scst_session *sess, aen->sess = sess; scst_sess_get(sess); - aen->lun = scst_pack_lun(unpacked_lun); + aen->lun = scst_pack_lun(unpacked_lun, sess->acg->addr_method); out: TRACE_EXIT_HRES((unsigned long)aen); @@ -2162,6 +2162,8 @@ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, goto out_free; } + acg->addr_method = SCST_LUN_ADDR_METHOD_PERIPHERAL; + #ifdef CONFIG_SCST_PROC TRACE_DBG("Adding acg %s to scst_acg_list", acg_name); list_add_tail(&acg->acg_list_entry, &scst_acg_list); @@ -4259,13 +4261,25 @@ out: } EXPORT_SYMBOL(scst_get_cdb_info); -/* Packs SCST LUN back to SCSI form using peripheral device addressing method */ -uint64_t scst_pack_lun(const uint64_t lun) +/* Packs SCST LUN back to SCSI form */ +uint64_t scst_pack_lun(const uint64_t lun, unsigned int addr_method) { - uint64_t res; + + uint64_t res = 0; uint16_t *p = (uint16_t *)&res; res = lun; + + if ((addr_method == SCST_LUN_ADDR_METHOD_FLAT) && (lun != 0)) { + /* + * Flat space: luns other than 0 should use flat space + * addressing method. + */ + *p = 0x7fff & *p; + *p = 0x4000 | *p; + } + /* Default is to use peripheral device addressing mode */ + *p = cpu_to_be16(*p); TRACE_EXIT_HRES((unsigned long)res); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 8c7fa1370..8e9a90eef 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -125,6 +125,10 @@ extern unsigned long scst_trace_flag; #define SCST_TGT_RETRY_TIMEOUT (3/2*HZ) +/* Definitions of symbolic constants for LUN addressing method */ +#define SCST_LUN_ADDR_METHOD_PERIPHERAL 0 +#define SCST_LUN_ADDR_METHOD_FLAT 1 + extern unsigned int scst_max_dev_cmd_mem; extern mempool_t *scst_mgmt_mempool; @@ -417,7 +421,7 @@ int scst_alloc_space(struct scst_cmd *cmd); int scst_lib_init(void); void scst_lib_exit(void); -uint64_t scst_pack_lun(const uint64_t lun); +uint64_t scst_pack_lun(const uint64_t lun, unsigned int addr_method); uint64_t scst_unpack_lun(const uint8_t *lun, int len); struct scst_mgmt_cmd *scst_alloc_mgmt_cmd(gfp_t gfp_mask); diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index 4b1f36acf..71914271f 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -37,7 +37,7 @@ static int scst_proc_init_groups(void); static void scst_proc_cleanup_groups(void); static int scst_proc_assign_handler(char *buf); -static int scst_proc_group_add(const char *p); +static int scst_proc_group_add(const char *p, unsigned int addr_method); static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc); static struct scst_proc_data scst_version_proc_data; @@ -45,6 +45,7 @@ static struct scst_proc_data scst_help_proc_data; static struct scst_proc_data scst_sgv_proc_data; static struct scst_proc_data scst_groups_names_proc_data; static struct scst_proc_data scst_groups_devices_proc_data; +static struct scst_proc_data scst_groups_addr_method_proc_data; static struct scst_proc_data scst_sessions_proc_data; static struct scst_proc_data scst_dev_handler_type_proc_data; static struct scst_proc_data scst_tgt_proc_data; @@ -67,6 +68,7 @@ static struct scst_proc_data scst_dev_handler_proc_data; #define SCST_PROC_GROUPS_ENTRY_NAME "groups" #define SCST_PROC_GROUPS_DEVICES_ENTRY_NAME "devices" #define SCST_PROC_GROUPS_USERS_ENTRY_NAME "names" +#define SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME "addr_method" #ifdef CONFIG_SCST_MEASURE_LATENCY #define SCST_PROC_LAT_ENTRY_NAME "latency" @@ -127,7 +129,7 @@ static struct scst_trace_log scst_proc_local_trace_tbl[] = { static char *scst_proc_help_string = " echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n" "\n" -" echo \"add_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n" +" echo \"add_group GROUP_NAME [FLAT]\" >/proc/scsi_tgt/scsi_tgt\n" " echo \"del_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n" " echo \"rename_group OLD_NAME NEW_NAME\" >/proc/scsi_tgt/scsi_tgt\n" "\n" @@ -811,17 +813,30 @@ static int scst_proc_group_add_tree(struct scst_acg *acg, const char *name) goto out; } + scst_groups_addr_method_proc_data.data = acg; + generic = scst_create_proc_entry(acg->acg_proc_root, + SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME, + &scst_groups_addr_method_proc_data); + if (!generic) { + PRINT_ERROR("Cannot init /proc/%s/%s/%s/%s", + SCST_PROC_ENTRY_NAME, + SCST_PROC_GROUPS_ENTRY_NAME, + name, SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME); + res = -ENOMEM; + goto out_remove; + } + scst_groups_devices_proc_data.data = acg; generic = scst_create_proc_entry(acg->acg_proc_root, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME, &scst_groups_devices_proc_data); if (!generic) { - PRINT_ERROR("cannot init /proc/%s/%s/%s/%s", + PRINT_ERROR("Cannot init /proc/%s/%s/%s/%s", SCST_PROC_ENTRY_NAME, SCST_PROC_GROUPS_ENTRY_NAME, name, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME); res = -ENOMEM; - goto out_remove; + goto out_remove0; } scst_groups_names_proc_data.data = acg; @@ -829,7 +844,7 @@ static int scst_proc_group_add_tree(struct scst_acg *acg, const char *name) SCST_PROC_GROUPS_USERS_ENTRY_NAME, &scst_groups_names_proc_data); if (!generic) { - PRINT_ERROR("cannot init /proc/%s/%s/%s/%s", + PRINT_ERROR("Cannot init /proc/%s/%s/%s/%s", SCST_PROC_ENTRY_NAME, SCST_PROC_GROUPS_ENTRY_NAME, name, SCST_PROC_GROUPS_USERS_ENTRY_NAME); @@ -845,6 +860,9 @@ out_remove1: remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME, acg->acg_proc_root); +out_remove0: + remove_proc_entry(SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME, + acg->acg_proc_root); out_remove: remove_proc_entry(name, scst_proc_groups_root); goto out; @@ -855,9 +873,9 @@ static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root, { TRACE_ENTRY(); + remove_proc_entry(SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME, acg_proc_root); remove_proc_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME, acg_proc_root); - remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME, - acg_proc_root); + remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME, acg_proc_root); remove_proc_entry(name, scst_proc_groups_root); TRACE_EXIT(); @@ -865,7 +883,7 @@ static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root, } /* The activity supposed to be suspended and scst_mutex held */ -static int scst_proc_group_add(const char *p) +static int scst_proc_group_add(const char *p, unsigned int addr_method) { int res = 0, len = strlen(p) + 1; struct scst_acg *acg; @@ -886,6 +904,8 @@ static int scst_proc_group_add(const char *p) goto out_free; } + acg->addr_method = addr_method; + res = scst_proc_group_add_tree(acg, p); if (res != 0) goto out_free_acg; @@ -1536,8 +1556,9 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, size_t length, loff_t *off) { int res, rc = 0, action; - char *buffer, *p, *pp; + char *buffer, *p, *pp, *ppp; struct scst_acg *a, *acg = NULL; + unsigned int addr_method = SCST_LUN_ADDR_METHOD_PERIPHERAL; TRACE_ENTRY(); @@ -1566,7 +1587,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, } /* - * Usage: echo "add_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt + * Usage: echo "add_group GROUP_NAME [FLAT]" >/proc/scsi_tgt/scsi_tgt * or echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt * or echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt" * or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt @@ -1603,6 +1624,9 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, res = length; + while (isspace(*p) && *p != '\0') + p++; + switch (action) { case SCST_PROC_ACTION_ADD_GROUP: case SCST_PROC_ACTION_DEL_GROUP: @@ -1618,6 +1642,29 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, if (*pp != '\0') { switch (action) { case SCST_PROC_ACTION_ADD_GROUP: + ppp = pp; + while (!isspace(*ppp) && *ppp != '\0') + ppp++; + if (*ppp != '\0') { + *ppp = '\0'; + ppp++; + while (isspace(*ppp) && *ppp != '\0') + ppp++; + if (*ppp != '\0') { + PRINT_ERROR("%s", "Too many " + "arguments"); + res = -EINVAL; + goto out_up_free; + } + } + if (strcasecmp(pp, "FLAT") != 0) { + PRINT_ERROR("Unexpected " + "argument %s", pp); + res = -EINVAL; + goto out_up_free; + } else + addr_method = SCST_LUN_ADDR_METHOD_FLAT; + break; case SCST_PROC_ACTION_DEL_GROUP: PRINT_ERROR("%s", "Too many " "arguments"); @@ -1650,7 +1697,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, res = -EINVAL; goto out_up_free; } - rc = scst_proc_group_add(p); + rc = scst_proc_group_add(p, addr_method); break; case SCST_PROC_ACTION_DEL_GROUP: if (acg == NULL) { @@ -2396,6 +2443,40 @@ static struct scst_proc_data scst_groups_names_proc_data = { .show = scst_groups_names_show, }; +static int scst_groups_addr_method_show(struct seq_file *seq, void *v) +{ + int res = 0; + struct scst_acg *acg = (struct scst_acg *)seq->private; + + TRACE_ENTRY(); + + if (mutex_lock_interruptible(&scst_mutex) != 0) { + res = -EINTR; + goto out; + } + + switch (acg->addr_method) { + case SCST_LUN_ADDR_METHOD_FLAT: + seq_printf(seq, "%s\n", "FLAT"); + break; + case SCST_LUN_ADDR_METHOD_PERIPHERAL: + seq_printf(seq, "%s\n", "PERIPHERAL"); + break; + default: + seq_printf(seq, "%s\n", "UNKNOWN"); + break; + } + + mutex_unlock(&scst_mutex); + +out: + TRACE_EXIT_RES(res); + return res; +} +static struct scst_proc_data scst_groups_addr_method_proc_data = { + SCST_DEF_RW_SEQ_OP(NULL) + .show = scst_groups_addr_method_show, +}; static int scst_groups_devices_show(struct seq_file *seq, void *v) { int res = 0; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 28fa2221f..3872e6fc9 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -106,6 +106,12 @@ static ssize_t scst_luns_mgmt_show(struct kobject *kobj, static ssize_t scst_luns_mgmt_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t scst_tgt_addr_method_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf); +static ssize_t scst_tgt_addr_method_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); @@ -127,6 +133,12 @@ static ssize_t scst_acg_ini_mgmt_show(struct kobject *kobj, static ssize_t scst_acg_ini_mgmt_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t scst_acg_addr_method_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf); +static ssize_t scst_acg_addr_method_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); static ssize_t scst_acn_file_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); @@ -513,10 +525,18 @@ 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_tgt_addr_method = + __ATTR(addr_method, S_IRUGO | S_IWUSR, scst_tgt_addr_method_show, + scst_tgt_addr_method_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 struct kobj_attribute scst_acg_addr_method = + __ATTR(addr_method, S_IRUGO | S_IWUSR, scst_acg_addr_method_show, + scst_acg_addr_method_store); + static ssize_t scst_tgt_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -672,6 +692,14 @@ int scst_create_tgt_sysfs(struct scst_tgt *tgt) goto out; } + retval = sysfs_create_file(&tgt->tgt_kobj, + &scst_tgt_addr_method.attr); + if (retval != 0) { + PRINT_ERROR("Can't add attribute %s for tgt %s", + scst_tgt_addr_method.attr.name, tgt->tgt_name); + goto out; + } + pattr = tgt->tgtt->tgt_attrs; if (pattr != NULL) { while (*pattr != NULL) { @@ -1652,12 +1680,76 @@ static ssize_t scst_luns_mgmt_store(struct kobject *kobj, tgt = container_of(kobj->parent, struct scst_tgt, tgt_kobj); acg = tgt->default_acg; + res = __scst_luns_mgmt_store(acg, kobj, buf, count); TRACE_EXIT_RES(res); return res; } +static ssize_t __scst_acg_addr_method_show(struct scst_acg *acg, char *buf) +{ + int res; + + switch (acg->addr_method) { + case SCST_LUN_ADDR_METHOD_FLAT: + res = sprintf(buf, "FLAT\n%s\n", SCST_SYSFS_KEY_MARK); + break; + case SCST_LUN_ADDR_METHOD_PERIPHERAL: + res = sprintf(buf, "PERIPHERAL\n"); + break; + default: + res = sprintf(buf, "UNKNOWN\n"); + break; + } + + return res; +} + +static ssize_t __scst_acg_addr_method_store(struct scst_acg *acg, + const char *buf, size_t count) +{ + int res = count; + + if (strncasecmp(buf, "FLAT", min_t(int, 4, count)) == 0) + acg->addr_method = SCST_LUN_ADDR_METHOD_FLAT; + else if (strncasecmp(buf, "PERIPHERAL", min_t(int, 10, count)) == 0) + acg->addr_method = SCST_LUN_ADDR_METHOD_PERIPHERAL; + else { + PRINT_ERROR("Unknown address method %s", buf); + res = -EINVAL; + } + return res; +} + +static ssize_t scst_tgt_addr_method_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_acg *acg; + struct scst_tgt *tgt; + + tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + acg = tgt->default_acg; + + return __scst_acg_addr_method_show(acg, buf); +} + +static ssize_t scst_tgt_addr_method_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res; + struct scst_acg *acg; + struct scst_tgt *tgt; + + tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + acg = tgt->default_acg; + + res = __scst_acg_addr_method_store(acg, buf, count); + + TRACE_EXIT_RES(res); + return res; +} + static int scst_create_acg_sysfs(struct scst_tgt *tgt, struct scst_acg *acg) { @@ -1705,6 +1797,14 @@ static int scst_create_acg_sysfs(struct scst_tgt *tgt, scst_acg_ini_mgmt.attr.name, tgt->tgt_name); goto out; } + + retval = sysfs_create_file(&acg->acg_kobj, &scst_acg_addr_method.attr); + if (retval != 0) { + PRINT_ERROR("Can't add tgt attr %s for tgt %s", + scst_acg_addr_method.attr.name, + tgt->tgt_name); + goto out; + } out: TRACE_EXIT_RES(retval); return retval; @@ -1732,13 +1832,35 @@ void scst_acg_sysfs_put(struct scst_acg *acg) return; } +static ssize_t scst_acg_addr_method_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_acg *acg; + + acg = container_of(kobj, struct scst_acg, acg_kobj); + + return __scst_acg_addr_method_show(acg, buf); +} + +static ssize_t scst_acg_addr_method_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res; + struct scst_acg *acg; + + acg = container_of(kobj, struct scst_acg, acg_kobj); + + res = __scst_acg_addr_method_store(acg, buf, count); + + TRACE_EXIT_RES(res); + return res; +} + static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - static char *help = "Usage: echo \"create GROUP_NAME\" " - ">mgmt\n" - " echo \"del GROUP_NAME\" " - ">mgmt\n"; + static char *help = "Usage: echo \"create GROUP_NAME\" >mgmt\n" + " echo \"del GROUP_NAME\" >mgmt\n"; return sprintf(buf, help); } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index be0231317..a8d65f84f 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -1481,8 +1481,15 @@ static int scst_report_luns_local(struct scst_cmd *cmd) buffer_size); goto out_put_hw_err; } - buffer[offs] = (tgt_dev->lun >> 8) & 0xff; - buffer[offs+1] = tgt_dev->lun & 0xff; + if ((cmd->sess->acg->addr_method == SCST_LUN_ADDR_METHOD_FLAT) && + (tgt_dev->lun != 0)) { + buffer[offs] = (tgt_dev->lun >> 8) & 0x3f; + buffer[offs] = buffer[offs] | 0x40; + buffer[offs+1] = tgt_dev->lun & 0xff; + } else { + buffer[offs] = (tgt_dev->lun >> 8) & 0xff; + buffer[offs+1] = tgt_dev->lun & 0xff; + } offs += 8; } inc_dev_cnt: