4 * Copyright (C) 2004 - 2009 Vladislav Bolkhovitin <vst@vlnb.net>
5 * Copyright (C) 2004 - 2005 Leonid Stoljar
6 * Copyright (C) 2007 - 2009 ID7 Ltd.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation, version 2
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include <linux/module.h>
21 #include <linux/init.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
24 #include <linux/list.h>
25 #include <linux/spinlock.h>
26 #include <linux/slab.h>
27 #include <linux/sched.h>
28 #include <linux/unistd.h>
29 #include <linux/string.h>
30 #include <linux/proc_fs.h>
31 #include <linux/seq_file.h>
34 #include "scst_priv.h"
37 static int scst_proc_init_groups(void);
38 static void scst_proc_cleanup_groups(void);
39 static int scst_proc_assign_handler(char *buf);
40 static int scst_proc_group_add(const char *p);
41 static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc);
43 static struct scst_proc_data scst_version_proc_data;
44 static struct scst_proc_data scst_help_proc_data;
45 static struct scst_proc_data scst_sgv_proc_data;
46 static struct scst_proc_data scst_groups_names_proc_data;
47 static struct scst_proc_data scst_groups_devices_proc_data;
48 static struct scst_proc_data scst_sessions_proc_data;
49 static struct scst_proc_data scst_dev_handler_type_proc_data;
50 static struct scst_proc_data scst_tgt_proc_data;
51 static struct scst_proc_data scst_threads_proc_data;
52 static struct scst_proc_data scst_scsi_tgt_proc_data;
53 static struct scst_proc_data scst_dev_handler_proc_data;
56 * Must be less than 4K page size, since our output routines
57 * use some slack for overruns
59 #define SCST_PROC_BLOCK_SIZE (PAGE_SIZE - 512)
61 #define SCST_PROC_LOG_ENTRY_NAME "trace_level"
62 #define SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME "type"
63 #define SCST_PROC_VERSION_NAME "version"
64 #define SCST_PROC_SESSIONS_NAME "sessions"
65 #define SCST_PROC_HELP_NAME "help"
66 #define SCST_PROC_THREADS_NAME "threads"
67 #define SCST_PROC_GROUPS_ENTRY_NAME "groups"
68 #define SCST_PROC_GROUPS_DEVICES_ENTRY_NAME "devices"
69 #define SCST_PROC_GROUPS_USERS_ENTRY_NAME "names"
71 #ifdef CONFIG_SCST_MEASURE_LATENCY
72 #define SCST_PROC_LAT_ENTRY_NAME "latency"
75 #define SCST_PROC_ACTION_ALL 1
76 #define SCST_PROC_ACTION_NONE 2
77 #define SCST_PROC_ACTION_DEFAULT 3
78 #define SCST_PROC_ACTION_SET 4
79 #define SCST_PROC_ACTION_ADD 5
80 #define SCST_PROC_ACTION_CLEAR 6
81 #define SCST_PROC_ACTION_MOVE 7
82 #define SCST_PROC_ACTION_DEL 8
83 #define SCST_PROC_ACTION_REPLACE 9
84 #define SCST_PROC_ACTION_VALUE 10
85 #define SCST_PROC_ACTION_ASSIGN 11
86 #define SCST_PROC_ACTION_ADD_GROUP 12
87 #define SCST_PROC_ACTION_DEL_GROUP 13
88 #define SCST_PROC_ACTION_RENAME_GROUP 14
90 static struct proc_dir_entry *scst_proc_scsi_tgt;
91 static struct proc_dir_entry *scst_proc_groups_root;
93 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
94 static struct scst_proc_data scst_log_proc_data;
96 static struct scst_proc_log scst_proc_trace_tbl[] =
98 { TRACE_OUT_OF_MEM, "out_of_mem" },
99 { TRACE_MINOR, "minor" },
100 { TRACE_SG_OP, "sg" },
101 { TRACE_MEMORY, "mem" },
102 { TRACE_BUFF, "buff" },
103 { TRACE_ENTRYEXIT, "entryexit" },
104 { TRACE_PID, "pid" },
105 { TRACE_LINE, "line" },
106 { TRACE_FUNCTION, "function" },
107 { TRACE_DEBUG, "debug" },
108 { TRACE_SPECIAL, "special" },
109 { TRACE_SCSI, "scsi" },
110 { TRACE_MGMT, "mgmt" },
111 { TRACE_MGMT_MINOR, "mgmt_minor" },
112 { TRACE_MGMT_DEBUG, "mgmt_dbg" },
116 static struct scst_proc_log scst_proc_local_trace_tbl[] =
118 { TRACE_RTRY, "retry" },
119 { TRACE_SCSI_SERIALIZING, "scsi_serializing" },
120 { TRACE_RCV_BOT, "recv_bot" },
121 { TRACE_SND_BOT, "send_bot" },
122 { TRACE_RCV_TOP, "recv_top" },
123 { TRACE_SND_TOP, "send_top" },
128 static char *scst_proc_help_string =
129 " echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
131 " echo \"add_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
132 " echo \"del_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
133 " echo \"rename_group OLD_NAME NEW_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
135 " echo \"add|del H:C:I:L lun [READ_ONLY]\""
136 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
137 " echo \"replace H:C:I:L lun [READ_ONLY]\""
138 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
139 " echo \"add|del V_NAME lun [READ_ONLY]\""
140 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
141 " echo \"replace V_NAME lun [READ_ONLY]\""
142 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
143 " echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
145 " echo \"add|del NAME\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n"
146 " echo \"move NAME NEW_GROUP_NAME\" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names\n"
147 " echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n"
149 " echo \"DEC|0xHEX|0OCT\" >/proc/scsi_tgt/threads\n"
150 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
152 " echo \"all|none|default\" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
153 " echo \"value DEC|0xHEX|0OCT\""
154 " >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
155 " echo \"set|add|del TOKEN\""
156 " >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
157 " where TOKEN is one of [debug,function,line,pid,entryexit,\n"
158 " buff,mem,sg,out_of_mem,special,scsi,mgmt,minor]\n"
159 " Additionally for /proc/scsi_tgt/trace_level there are these TOKENs\n"
160 " [scsi_serializing,retry,recv_bot,send_bot,recv_top,send_top]\n"
164 static char *scst_proc_dev_handler_type[] =
166 "Direct-access device (e.g., magnetic disk)",
167 "Sequential-access device (e.g., magnetic tape)",
170 "Write-once device (e.g., some optical disks)",
172 "Scanner device (obsolete)",
173 "Optical memory device (e.g., some optical disks)",
174 "Medium changer device (e.g., jukeboxes)",
175 "Communications device (obsolete)",
176 "Defined by ASC IT8 (Graphic arts pre-press devices)",
177 "Defined by ASC IT8 (Graphic arts pre-press devices)",
178 "Storage array controller device (e.g., RAID)",
179 "Enclosure services device",
180 "Simplified direct-access device (e.g., magnetic disk)",
181 "Optical card reader/writer device"
184 static DEFINE_MUTEX(scst_proc_mutex);
186 #include <linux/ctype.h>
188 #if !defined(CONFIG_PPC) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3)
190 * If strcasecmp() and strncasecmp() have already been declared in
191 * <linux/string.h>, do not redefine these functions. Declarations for these
192 * functions are present in the <linux/string.h> header of the following
194 * - The PPC kernel headers for all kernel versions supported by SCST.
195 * - Kernel version 2.6.22 and later for all architectures.
196 * - RHEL 5.3 and later.
198 * Notes about the above preprocessor statement:
199 * - We can't use RHEL_RELEASE_CODE(5, 3) because it would trigger an error on
200 * non-RHEL/CentOS systems -- this expression would expand to "(5,3)".
201 * - There is no space between the minus sign and the zero in the expression
202 * "RHEL_RELEASE_CODE -0" such that it expands to a syntactically valid
203 * expression on non-RHEL/CentOS systems ("-0").
204 * - The above statement has been put on one long line because as of r800
205 * scripts/specialize-patch does not yet handle multi-line preprocessor
206 * statements correctly.
209 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
210 static int strcasecmp(const char *s1, const char *s2)
216 } while (c1 == c2 && c1 != 0);
221 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
222 static int strncasecmp(const char *s1, const char *s2, int n)
224 static int strncasecmp(const char *s1, const char *s2, size_t n)
231 } while ((--n > 0) && c1 == c2 && c1 != 0);
235 #endif /* !CONFIG_PPC && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) */
237 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
239 static DEFINE_MUTEX(scst_log_mutex);
241 int scst_proc_log_entry_write(struct file *file, const char __user *buf,
242 unsigned long length, unsigned long *log_level,
243 unsigned long default_level, const struct scst_proc_log *tbl)
247 unsigned long level = 0, oldlevel;
248 char *buffer, *p, *e;
249 const struct scst_proc_log *t;
250 char *data = (char *)PDE(file->f_dentry->d_inode)->data;
254 if (length > SCST_PROC_BLOCK_SIZE) {
262 buffer = (char *)__get_free_page(GFP_KERNEL);
267 if (copy_from_user(buffer, buf, length)) {
271 if (length < PAGE_SIZE) {
272 buffer[length] = '\0';
273 } else if (buffer[PAGE_SIZE-1]) {
280 * echo "all|none|default" >/proc/scsi_tgt/trace_level
281 * echo "value DEC|0xHEX|0OCT" >/proc/scsi_tgt/trace_level
282 * echo "set|add|clear|del TOKEN" >/proc/scsi_tgt/trace_level
283 * where TOKEN is one of [debug,function,line,pid,entryexit,
284 * buff,mem,sg,out_of_mem,retry,
285 * scsi_serializing,special,scsi,mgmt,minor,...]
288 if (!strncasecmp("all", p, 3)) {
289 action = SCST_PROC_ACTION_ALL;
290 } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) {
291 action = SCST_PROC_ACTION_NONE;
292 } else if (!strncasecmp("default", p, 7)) {
293 action = SCST_PROC_ACTION_DEFAULT;
294 } else if (!strncasecmp("set ", p, 4)) {
296 action = SCST_PROC_ACTION_SET;
297 } else if (!strncasecmp("add ", p, 4)) {
299 action = SCST_PROC_ACTION_ADD;
300 } else if (!strncasecmp("del ", p, 4)) {
302 action = SCST_PROC_ACTION_DEL;
303 } else if (!strncasecmp("value ", p, 6)) {
305 action = SCST_PROC_ACTION_VALUE;
307 if (p[strlen(p) - 1] == '\n')
308 p[strlen(p) - 1] = '\0';
309 PRINT_ERROR("Unknown action \"%s\"", p);
315 case SCST_PROC_ACTION_ALL:
318 case SCST_PROC_ACTION_DEFAULT:
319 level = default_level;
321 case SCST_PROC_ACTION_NONE:
324 case SCST_PROC_ACTION_SET:
325 case SCST_PROC_ACTION_ADD:
326 case SCST_PROC_ACTION_DEL:
327 while (isspace(*p) && *p != '\0')
330 while (!isspace(*e) && *e != '\0')
336 if (!strcasecmp(p, t->token)) {
344 t = scst_proc_trace_tbl;
346 if (!strcasecmp(p, t->token)) {
354 PRINT_ERROR("Unknown token \"%s\"", p);
359 case SCST_PROC_ACTION_VALUE:
360 while (isspace(*p) && *p != '\0')
362 level = simple_strtoul(p, NULL, 0);
366 oldlevel = *log_level;
369 case SCST_PROC_ACTION_ADD:
372 case SCST_PROC_ACTION_DEL:
373 *log_level &= ~level;
380 PRINT_INFO("Changed trace level for \"%s\": "
381 "old 0x%08lx, new 0x%08lx",
382 (char *)data, oldlevel, *log_level);
385 free_page((unsigned long)buffer);
390 EXPORT_SYMBOL(scst_proc_log_entry_write);
392 static ssize_t scst_proc_scsi_tgt_gen_write_log(struct file *file,
393 const char __user *buf,
394 size_t length, loff_t *off)
400 if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
405 res = scst_proc_log_entry_write(file, buf, length,
406 &trace_flag, SCST_DEFAULT_LOG_FLAGS,
407 scst_proc_local_trace_tbl);
409 mutex_unlock(&scst_log_mutex);
416 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
418 #ifdef CONFIG_SCST_MEASURE_LATENCY
420 static int lat_info_show(struct seq_file *seq, void *v)
423 struct scst_acg *acg;
424 struct scst_session *sess;
428 if (mutex_lock_interruptible(&scst_mutex) != 0) {
433 seq_printf(seq, "%-20s %-45s %-15s %15s\n",
437 "Processing latency (ns)");
439 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
440 list_for_each_entry(sess, &acg->acg_sess_list,
441 acg_sess_list_entry) {
442 unsigned long proc_lat = 0, scst_lat = 0;
443 uint64_t proc_time, scst_time;
444 unsigned int processed_cmds;
446 spin_lock_bh(&sess->meas_lock);
447 proc_time = sess->processing_time;
448 scst_time = sess->scst_time;
449 processed_cmds = sess->processed_cmds;
450 spin_unlock_bh(&sess->meas_lock);
452 TRACE_DBG("sess %p, scst_time %lld, proc_time %lld, "
453 "processed_cmds %d", sess, scst_time,
454 proc_time, processed_cmds);
456 #if BITS_PER_LONG == 32
457 /* Unfortunately, do_div() doesn't work too well */
458 while (((proc_time & 0xFFFFFFFF00000000LL) != 0) ||
459 ((scst_time & 0xFFFFFFFF00000000LL) != 0)) {
460 TRACE_DBG("%s", "Gathered time too big");
463 processed_cmds >>= 1;
467 if (sess->processed_cmds != 0) {
468 proc_lat = (unsigned long)proc_time /
470 scst_lat = (unsigned long)scst_time /
474 seq_printf(seq, "%-20s %-45s %-15ld %-15ld\n",
475 sess->tgt->tgtt->name,
476 sess->initiator_name,
481 mutex_unlock(&scst_mutex);
488 static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file,
489 const char __user *buf,
490 size_t length, loff_t *off)
493 struct scst_acg *acg;
494 struct scst_session *sess;
498 if (mutex_lock_interruptible(&scst_mutex) != 0) {
503 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
504 list_for_each_entry(sess, &acg->acg_sess_list,
505 acg_sess_list_entry) {
506 PRINT_INFO("Zeroing latency statistics for initiator"
508 sess->initiator_name);
509 spin_lock_bh(&sess->meas_lock);
510 sess->processing_time = 0;
512 sess->processed_cmds = 0;
513 spin_unlock_bh(&sess->meas_lock);
517 mutex_unlock(&scst_mutex);
524 static struct scst_proc_data scst_lat_proc_data = {
525 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_lat)
526 .show = lat_info_show,
530 #endif /* CONFIG_SCST_MEASURE_LATENCY */
532 static int __init scst_proc_init_module_log(void)
535 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) || \
536 defined(CONFIG_SCST_MEASURE_LATENCY)
537 struct proc_dir_entry *generic;
542 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
543 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
544 SCST_PROC_LOG_ENTRY_NAME,
545 &scst_log_proc_data);
547 PRINT_ERROR("cannot init /proc/%s/%s",
548 SCST_PROC_ENTRY_NAME, SCST_PROC_LOG_ENTRY_NAME);
553 #ifdef CONFIG_SCST_MEASURE_LATENCY
555 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
556 SCST_PROC_LAT_ENTRY_NAME,
557 &scst_lat_proc_data);
559 PRINT_ERROR("cannot init /proc/%s/%s",
560 SCST_PROC_ENTRY_NAME,
561 SCST_PROC_LAT_ENTRY_NAME);
571 static void scst_proc_cleanup_module_log(void)
575 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
576 remove_proc_entry(SCST_PROC_LOG_ENTRY_NAME, scst_proc_scsi_tgt);
579 #ifdef CONFIG_SCST_MEASURE_LATENCY
580 remove_proc_entry(SCST_PROC_LAT_ENTRY_NAME, scst_proc_scsi_tgt);
587 static int scst_proc_group_add_tree(struct scst_acg *acg, const char *name)
590 struct proc_dir_entry *generic;
594 acg->acg_proc_root = proc_mkdir(name, scst_proc_groups_root);
595 if (acg->acg_proc_root == NULL) {
596 PRINT_ERROR("Not enough memory to register %s entry in "
597 "/proc/%s/%s", name, SCST_PROC_ENTRY_NAME,
598 SCST_PROC_GROUPS_ENTRY_NAME);
602 scst_groups_devices_proc_data.data = acg;
603 generic = scst_create_proc_entry(acg->acg_proc_root,
604 SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
605 &scst_groups_devices_proc_data);
607 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
608 SCST_PROC_ENTRY_NAME,
609 SCST_PROC_GROUPS_ENTRY_NAME,
610 name, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME);
615 scst_groups_names_proc_data.data = acg;
616 generic = scst_create_proc_entry(acg->acg_proc_root,
617 SCST_PROC_GROUPS_USERS_ENTRY_NAME,
618 &scst_groups_names_proc_data);
620 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
621 SCST_PROC_ENTRY_NAME,
622 SCST_PROC_GROUPS_ENTRY_NAME,
623 name, SCST_PROC_GROUPS_USERS_ENTRY_NAME);
633 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
637 remove_proc_entry(name, scst_proc_groups_root);
641 static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
646 remove_proc_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME, acg_proc_root);
647 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
649 remove_proc_entry(name, scst_proc_groups_root);
655 /* The activity supposed to be suspended and scst_mutex held */
656 static int scst_proc_group_add(const char *p)
658 int res = 0, len = strlen(p) + 1;
659 struct scst_acg *acg;
664 name = kmalloc(len, GFP_KERNEL);
666 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of name failed");
669 strncpy(name, p, len);
671 acg = scst_alloc_add_acg(name);
673 PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", name);
677 res = scst_proc_group_add_tree(acg, p);
686 scst_proc_del_free_acg(acg, 0);
696 /* The activity supposed to be suspended and scst_mutex held */
697 static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc)
700 struct proc_dir_entry *acg_proc_root = acg->acg_proc_root;
705 if (acg != scst_default_acg) {
706 name = acg->acg_name;
707 res = scst_destroy_acg(acg);
710 scst_proc_del_acg_tree(acg_proc_root, name);
719 /* The activity supposed to be suspended and scst_mutex held */
720 static int scst_proc_rename_acg(struct scst_acg *acg, const char *new_name)
722 int res = 0, len = strlen(new_name) + 1;
724 struct proc_dir_entry *old_acg_proc_root = acg->acg_proc_root;
728 name = kmalloc(len, GFP_KERNEL);
730 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of new name failed");
733 strncpy(name, new_name, len);
735 res = scst_proc_group_add_tree(acg, new_name);
739 scst_proc_del_acg_tree(old_acg_proc_root, acg->acg_name);
741 kfree(acg->acg_name);
742 acg->acg_name = name;
744 scst_check_reassign_sessions();
758 static int __init scst_proc_init_groups(void)
764 /* create the proc directory entry for the device */
765 scst_proc_groups_root = proc_mkdir(SCST_PROC_GROUPS_ENTRY_NAME,
767 if (scst_proc_groups_root == NULL) {
768 PRINT_ERROR("Not enough memory to register %s entry in "
769 "/proc/%s", SCST_PROC_GROUPS_ENTRY_NAME,
770 SCST_PROC_ENTRY_NAME);
774 res = scst_proc_group_add_tree(scst_default_acg,
775 SCST_DEFAULT_ACG_NAME);
784 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
791 static void scst_proc_cleanup_groups(void)
793 struct scst_acg *acg_tmp, *acg;
797 /* remove all groups (dir & entries) */
798 list_for_each_entry_safe(acg, acg_tmp, &scst_acg_list,
799 scst_acg_list_entry) {
800 scst_proc_del_free_acg(acg, 1);
803 scst_proc_del_acg_tree(scst_default_acg->acg_proc_root,
804 SCST_DEFAULT_ACG_NAME);
805 TRACE_DBG("remove_proc_entry(%s, %p)",
806 SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
807 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
812 static int __init scst_proc_init_sgv(void)
815 struct proc_dir_entry *pr;
819 pr = scst_create_proc_entry(scst_proc_scsi_tgt, "sgv",
820 &scst_sgv_proc_data);
822 PRINT_ERROR("%s", "cannot create sgv /proc entry");
830 static void __exit scst_proc_cleanup_sgv(void)
833 remove_proc_entry("sgv", scst_proc_scsi_tgt);
837 int __init scst_proc_init_module(void)
840 struct proc_dir_entry *generic;
844 scst_proc_scsi_tgt = proc_mkdir(SCST_PROC_ENTRY_NAME, NULL);
845 if (!scst_proc_scsi_tgt) {
846 PRINT_ERROR("cannot init /proc/%s", SCST_PROC_ENTRY_NAME);
850 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
851 SCST_PROC_ENTRY_NAME,
852 &scst_tgt_proc_data);
854 PRINT_ERROR("cannot init /proc/%s/%s",
855 SCST_PROC_ENTRY_NAME, SCST_PROC_ENTRY_NAME);
859 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
860 SCST_PROC_VERSION_NAME,
861 &scst_version_proc_data);
863 PRINT_ERROR("cannot init /proc/%s/%s",
864 SCST_PROC_ENTRY_NAME, SCST_PROC_VERSION_NAME);
868 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
869 SCST_PROC_SESSIONS_NAME,
870 &scst_sessions_proc_data);
872 PRINT_ERROR("cannot init /proc/%s/%s",
873 SCST_PROC_ENTRY_NAME, SCST_PROC_SESSIONS_NAME);
877 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
879 &scst_help_proc_data);
881 PRINT_ERROR("cannot init /proc/%s/%s",
882 SCST_PROC_ENTRY_NAME, SCST_PROC_HELP_NAME);
886 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
887 SCST_PROC_THREADS_NAME,
888 &scst_threads_proc_data);
890 PRINT_ERROR("cannot init /proc/%s/%s",
891 SCST_PROC_ENTRY_NAME, SCST_PROC_THREADS_NAME);
895 if (scst_proc_init_module_log() < 0)
898 if (scst_proc_init_groups() < 0)
901 if (scst_proc_init_sgv() < 0)
909 scst_proc_cleanup_groups();
912 scst_proc_cleanup_module_log();
915 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
918 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
921 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
924 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
927 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
930 remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
937 void __exit scst_proc_cleanup_module(void)
941 /* We may not bother about locks here */
942 scst_proc_cleanup_sgv();
943 scst_proc_cleanup_groups();
944 scst_proc_cleanup_module_log();
945 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
946 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
947 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
948 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
949 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
950 remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
955 static ssize_t scst_proc_threads_write(struct file *file,
956 const char __user *buf,
957 size_t length, loff_t *off)
960 int oldtn, newtn, delta;
965 if (length > SCST_PROC_BLOCK_SIZE) {
973 buffer = (char *)__get_free_page(GFP_KERNEL);
978 if (copy_from_user(buffer, buf, length)) {
982 if (length < PAGE_SIZE) {
983 buffer[length] = '\0';
984 } else if (buffer[PAGE_SIZE-1]) {
989 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
994 mutex_lock(&scst_global_threads_mutex);
996 oldtn = scst_nr_global_threads;
997 newtn = simple_strtoul(buffer, NULL, 0);
999 PRINT_ERROR("Illegal threads num value %d", newtn);
1001 goto out_up_thr_free;
1003 delta = newtn - oldtn;
1005 __scst_del_global_threads(-delta);
1007 __scst_add_global_threads(delta);
1009 PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
1012 mutex_unlock(&scst_global_threads_mutex);
1014 mutex_unlock(&scst_proc_mutex);
1017 free_page((unsigned long)buffer);
1019 TRACE_EXIT_RES(res);
1023 int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt)
1029 /* create the proc directory entry for the device */
1030 vtt->proc_tgt_root = proc_mkdir(vtt->name, scst_proc_scsi_tgt);
1031 if (vtt->proc_tgt_root == NULL) {
1032 PRINT_ERROR("Not enough memory to register SCSI target %s "
1033 "in /proc/%s", vtt->name, SCST_PROC_ENTRY_NAME);
1038 TRACE_EXIT_RES(res);
1046 void scst_cleanup_proc_target_dir_entries(struct scst_tgt_template *vtt)
1050 remove_proc_entry(vtt->name, scst_proc_scsi_tgt);
1056 /* Called under scst_mutex */
1057 int scst_build_proc_target_entries(struct scst_tgt *vtt)
1060 struct proc_dir_entry *p;
1065 if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1066 /* create the proc file entry for the device */
1067 scnprintf(name, sizeof(name), "%d", vtt->tgtt->proc_dev_num);
1068 scst_scsi_tgt_proc_data.data = (void *)vtt;
1069 p = scst_create_proc_entry(vtt->tgtt->proc_tgt_root,
1071 &scst_scsi_tgt_proc_data);
1073 PRINT_ERROR("Not enough memory to register SCSI "
1074 "target entry %s in /proc/%s/%s", name,
1075 SCST_PROC_ENTRY_NAME, vtt->tgtt->name);
1079 vtt->proc_num = vtt->tgtt->proc_dev_num;
1080 vtt->tgtt->proc_dev_num++;
1084 TRACE_EXIT_RES(res);
1088 void scst_cleanup_proc_target_entries(struct scst_tgt *vtt)
1094 if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1095 scnprintf(name, sizeof(name), "%d", vtt->proc_num);
1096 remove_proc_entry(name, vtt->tgtt->proc_tgt_root);
1103 static ssize_t scst_proc_scsi_tgt_write(struct file *file,
1104 const char __user *buf,
1105 size_t length, loff_t *off)
1107 struct scst_tgt *vtt =
1108 (struct scst_tgt *)PDE(file->f_dentry->d_inode)->data;
1116 if (vtt->tgtt->write_proc == NULL) {
1121 if (length > SCST_PROC_BLOCK_SIZE) {
1129 buffer = (char *)__get_free_page(GFP_KERNEL);
1134 if (copy_from_user(buffer, buf, length)) {
1138 if (length < PAGE_SIZE) {
1139 buffer[length] = '\0';
1140 } else if (buffer[PAGE_SIZE-1]) {
1145 TRACE_BUFFER("Buffer", buffer, length);
1147 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1152 res = vtt->tgtt->write_proc(buffer, &start, 0, length, &eof, vtt);
1154 mutex_unlock(&scst_proc_mutex);
1157 free_page((unsigned long)buffer);
1159 TRACE_EXIT_RES(res);
1163 int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1166 struct proc_dir_entry *p;
1170 sBUG_ON(dev_type->proc_dev_type_root);
1172 /* create the proc directory entry for the dev type handler */
1173 dev_type->proc_dev_type_root = proc_mkdir(dev_type->name,
1174 scst_proc_scsi_tgt);
1175 if (dev_type->proc_dev_type_root == NULL) {
1176 PRINT_ERROR("Not enough memory to register dev handler dir "
1177 "%s in /proc/%s", dev_type->name, SCST_PROC_ENTRY_NAME);
1181 scst_dev_handler_type_proc_data.data = dev_type;
1182 if (dev_type->type >= 0) {
1183 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1184 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1185 &scst_dev_handler_type_proc_data);
1187 PRINT_ERROR("Not enough memory to register dev "
1188 "handler entry %s in /proc/%s/%s",
1189 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1190 SCST_PROC_ENTRY_NAME, dev_type->name);
1195 if (dev_type->read_proc || dev_type->write_proc) {
1196 /* create the proc file entry for the dev type handler */
1197 scst_dev_handler_proc_data.data = (void *)dev_type;
1198 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1200 &scst_dev_handler_proc_data);
1202 PRINT_ERROR("Not enough memory to register dev "
1203 "handler entry %s in /proc/%s/%s", dev_type->name,
1204 SCST_PROC_ENTRY_NAME, dev_type->name);
1210 TRACE_EXIT_RES(res);
1214 if (dev_type->type >= 0)
1215 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1216 dev_type->proc_dev_type_root);
1219 remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1226 void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1230 sBUG_ON(dev_type->proc_dev_type_root == NULL);
1232 if (dev_type->type >= 0) {
1233 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1234 dev_type->proc_dev_type_root);
1236 if (dev_type->read_proc || dev_type->write_proc)
1237 remove_proc_entry(dev_type->name, dev_type->proc_dev_type_root);
1238 remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1239 dev_type->proc_dev_type_root = NULL;
1245 static ssize_t scst_proc_scsi_dev_handler_write(struct file *file,
1246 const char __user *buf,
1247 size_t length, loff_t *off)
1249 struct scst_dev_type *dev_type =
1250 (struct scst_dev_type *)PDE(file->f_dentry->d_inode)->data;
1258 if (dev_type->write_proc == NULL) {
1263 if (length > SCST_PROC_BLOCK_SIZE) {
1272 buffer = (char *)__get_free_page(GFP_KERNEL);
1278 if (copy_from_user(buffer, buf, length)) {
1282 if (length < PAGE_SIZE) {
1283 buffer[length] = '\0';
1284 } else if (buffer[PAGE_SIZE-1]) {
1289 TRACE_BUFFER("Buffer", buffer, length);
1291 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1296 res = dev_type->write_proc(buffer, &start, 0, length, &eof, dev_type);
1298 mutex_unlock(&scst_proc_mutex);
1301 free_page((unsigned long)buffer);
1304 TRACE_EXIT_RES(res);
1308 static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file,
1309 const char __user *buf,
1310 size_t length, loff_t *off)
1312 int res, rc = 0, action;
1313 char *buffer, *p, *pp;
1314 struct scst_acg *a, *acg = NULL;
1318 if (length > SCST_PROC_BLOCK_SIZE) {
1326 buffer = (char *)__get_free_page(GFP_KERNEL);
1331 if (copy_from_user(buffer, buf, length)) {
1335 if (length < PAGE_SIZE) {
1336 buffer[length] = '\0';
1337 } else if (buffer[PAGE_SIZE-1]) {
1343 * Usage: echo "add_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1344 * or echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1345 * or echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt"
1346 * or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt
1349 if (p[strlen(p) - 1] == '\n')
1350 p[strlen(p) - 1] = '\0';
1351 if (!strncasecmp("assign ", p, 7)) {
1353 action = SCST_PROC_ACTION_ASSIGN;
1354 } else if (!strncasecmp("add_group ", p, 10)) {
1356 action = SCST_PROC_ACTION_ADD_GROUP;
1357 } else if (!strncasecmp("del_group ", p, 10)) {
1359 action = SCST_PROC_ACTION_DEL_GROUP;
1360 } else if (!strncasecmp("rename_group ", p, 13)) {
1362 action = SCST_PROC_ACTION_RENAME_GROUP;
1364 PRINT_ERROR("Unknown action \"%s\"", p);
1369 res = scst_suspend_activity(true);
1373 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1375 goto out_free_resume;
1381 case SCST_PROC_ACTION_ADD_GROUP:
1382 case SCST_PROC_ACTION_DEL_GROUP:
1383 case SCST_PROC_ACTION_RENAME_GROUP:
1385 while (!isspace(*pp) && *pp != '\0')
1390 while (isspace(*pp) && *pp != '\0')
1394 case SCST_PROC_ACTION_ADD_GROUP:
1395 case SCST_PROC_ACTION_DEL_GROUP:
1396 PRINT_ERROR("%s", "Too many "
1404 if (strcmp(p, SCST_DEFAULT_ACG_NAME) == 0) {
1405 PRINT_ERROR("Attempt to add/delete/rename predefined "
1411 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1412 if (strcmp(a->acg_name, p) == 0) {
1413 TRACE_DBG("group (acg) %p %s found",
1421 case SCST_PROC_ACTION_ADD_GROUP:
1423 PRINT_ERROR("acg name %s exist", p);
1427 rc = scst_proc_group_add(p);
1429 case SCST_PROC_ACTION_DEL_GROUP:
1431 PRINT_ERROR("acg name %s not found", p);
1435 rc = scst_proc_del_free_acg(acg, 1);
1437 case SCST_PROC_ACTION_RENAME_GROUP:
1439 PRINT_ERROR("acg name %s not found", p);
1445 while (!isspace(*pp) && *pp != '\0')
1450 while (isspace(*pp) && *pp != '\0')
1453 PRINT_ERROR("%s", "Too many arguments");
1458 rc = scst_proc_rename_acg(acg, p);
1462 case SCST_PROC_ACTION_ASSIGN:
1463 rc = scst_proc_assign_handler(p);
1471 mutex_unlock(&scst_mutex);
1474 scst_resume_activity();
1477 free_page((unsigned long)buffer);
1480 TRACE_EXIT_RES(res);
1484 /* The activity supposed to be suspended and scst_mutex held */
1485 static int scst_proc_assign_handler(char *buf)
1488 char *p = buf, *e, *ee;
1489 unsigned long host, channel = 0, id = 0, lun = 0;
1490 struct scst_device *d, *dev = NULL;
1491 struct scst_dev_type *dt, *handler = NULL;
1495 while (isspace(*p) && *p != '\0')
1498 host = simple_strtoul(p, &p, 0);
1499 if ((host == ULONG_MAX) || (*p != ':'))
1502 channel = simple_strtoul(p, &p, 0);
1503 if ((channel == ULONG_MAX) || (*p != ':'))
1506 id = simple_strtoul(p, &p, 0);
1507 if ((channel == ULONG_MAX) || (*p != ':'))
1510 lun = simple_strtoul(p, &p, 0);
1511 if (lun == ULONG_MAX)
1516 while (isspace(*e) && *e != '\0')
1519 while (!isspace(*ee) && *ee != '\0')
1523 TRACE_DBG("Dev %ld:%ld:%ld:%ld, handler %s", host, channel, id, lun, e);
1525 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1526 if ((d->virt_id == 0) &&
1527 d->scsi_dev->host->host_no == host &&
1528 d->scsi_dev->channel == channel &&
1529 d->scsi_dev->id == id &&
1530 d->scsi_dev->lun == lun) {
1532 TRACE_DBG("Dev %p (%ld:%ld:%ld:%ld) found",
1533 dev, host, channel, id, lun);
1539 PRINT_ERROR("Device %ld:%ld:%ld:%ld not found",
1540 host, channel, id, lun);
1545 list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
1546 if (!strcmp(dt->name, e)) {
1548 TRACE_DBG("Dev handler %p with name %s found",
1554 if (handler == NULL) {
1555 PRINT_ERROR("Handler %s not found", e);
1560 if (dev->scsi_dev->type != handler->type) {
1561 PRINT_ERROR("Type %d of device %s differs from type "
1562 "%d of dev handler %s", dev->type,
1563 dev->handler->name, handler->type, handler->name);
1568 res = scst_assign_dev_handler(dev, handler);
1571 TRACE_EXIT_RES(res);
1575 PRINT_ERROR("Syntax error on %s", p);
1580 static ssize_t scst_proc_groups_devices_write(struct file *file,
1581 const char __user *buf,
1582 size_t length, loff_t *off)
1584 int res, action, virt = 0, rc, read_only = 0;
1585 char *buffer, *p, *e = NULL;
1586 unsigned int host, channel = 0, id = 0, lun = 0, virt_lun;
1587 struct scst_acg *acg =
1588 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1589 struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
1590 struct scst_device *d, *dev = NULL;
1594 if (length > SCST_PROC_BLOCK_SIZE) {
1602 buffer = (char *)__get_free_page(GFP_KERNEL);
1607 if (copy_from_user(buffer, buf, length)) {
1611 if (length < PAGE_SIZE) {
1612 buffer[length] = '\0';
1613 } else if (buffer[PAGE_SIZE-1]) {
1619 * Usage: echo "add|del H:C:I:L lun [READ_ONLY]" \
1620 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1621 * or echo "replace H:C:I:L lun [READ_ONLY]" \
1622 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1623 * or echo "add|del V_NAME lun [READ_ONLY]" \
1624 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1625 * or echo "replace V_NAME lun [READ_ONLY]" \
1626 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1627 * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/devices
1630 if (p[strlen(p) - 1] == '\n')
1631 p[strlen(p) - 1] = '\0';
1632 if (!strncasecmp("clear", p, 5)) {
1633 action = SCST_PROC_ACTION_CLEAR;
1634 } else if (!strncasecmp("add ", p, 4)) {
1636 action = SCST_PROC_ACTION_ADD;
1637 } else if (!strncasecmp("del ", p, 4)) {
1639 action = SCST_PROC_ACTION_DEL;
1640 } else if (!strncasecmp("replace ", p, 8)) {
1642 action = SCST_PROC_ACTION_REPLACE;
1644 PRINT_ERROR("Unknown action \"%s\"", p);
1649 res = scst_suspend_activity(true);
1653 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1655 goto out_free_resume;
1661 case SCST_PROC_ACTION_ADD:
1662 case SCST_PROC_ACTION_DEL:
1663 case SCST_PROC_ACTION_REPLACE:
1664 while (isspace(*p) && *p != '\0')
1667 host = simple_strtoul(p, &p, 0);
1669 channel = simple_strtoul(p + 1, &p, 0);
1670 id = simple_strtoul(p + 1, &p, 0);
1671 lun = simple_strtoul(p + 1, &p, 0);
1675 p = e; /* restore p */
1676 while (!isspace(*e) && *e != '\0')
1681 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1683 if (d->virt_id && !strcmp(d->virt_name, p)) {
1685 TRACE_DBG("Virt device %p (%s) found",
1691 d->scsi_dev->host->host_no == host &&
1692 d->scsi_dev->channel == channel &&
1693 d->scsi_dev->id == id &&
1694 d->scsi_dev->lun == lun) {
1696 TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
1697 dev, host, channel, id, lun);
1704 PRINT_ERROR("Virt device %s not found", p);
1706 PRINT_ERROR("Device %d:%d:%d:%d not found",
1707 host, channel, id, lun);
1715 /* ToDo: create separate functions */
1718 case SCST_PROC_ACTION_ADD:
1719 case SCST_PROC_ACTION_REPLACE:
1721 bool dev_replaced = false;
1724 while (isspace(*e) && *e != '\0')
1726 virt_lun = simple_strtoul(e, &e, 0);
1728 while (isspace(*e) && *e != '\0')
1732 if (!strncasecmp("READ_ONLY", e, 9))
1735 PRINT_ERROR("Unknown option \"%s\"", e);
1741 list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
1742 acg_dev_list_entry) {
1743 if (acg_dev_tmp->lun == virt_lun) {
1744 acg_dev = acg_dev_tmp;
1748 if (acg_dev != NULL) {
1749 if (action == SCST_PROC_ACTION_ADD) {
1750 PRINT_ERROR("virt lun %d already exists in "
1751 "group %s", virt_lun, acg->acg_name);
1756 rc = scst_acg_remove_dev(acg, acg_dev->dev,
1762 dev_replaced = true;
1766 rc = scst_acg_add_dev(acg, dev, virt_lun, read_only,
1767 action == SCST_PROC_ACTION_ADD);
1774 struct scst_tgt_dev *tgt_dev;
1776 list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
1777 dev_tgt_dev_list_entry) {
1778 if ((tgt_dev->acg_dev->acg == acg) &&
1779 (tgt_dev->lun == virt_lun)) {
1780 TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED"
1781 " on tgt_dev %p", tgt_dev);
1782 scst_gen_aen_or_ua(tgt_dev,
1783 SCST_LOAD_SENSE(scst_sense_inquery_data_changed));
1789 case SCST_PROC_ACTION_DEL:
1790 rc = scst_acg_remove_dev(acg, dev, true);
1796 case SCST_PROC_ACTION_CLEAR:
1797 list_for_each_entry_safe(acg_dev, acg_dev_tmp,
1799 acg_dev_list_entry) {
1800 rc = scst_acg_remove_dev(acg, acg_dev->dev,
1801 list_is_last(&acg_dev->acg_dev_list_entry,
1802 &acg->acg_dev_list));
1812 mutex_unlock(&scst_mutex);
1815 scst_resume_activity();
1818 free_page((unsigned long)buffer);
1821 TRACE_EXIT_RES(res);
1825 static ssize_t scst_proc_groups_names_write(struct file *file,
1826 const char __user *buf,
1827 size_t length, loff_t *off)
1829 int res = length, rc = 0, action;
1830 char *buffer, *p, *pp = NULL;
1831 struct scst_acg *acg =
1832 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1833 struct scst_acn *n, *nn;
1837 if (length > SCST_PROC_BLOCK_SIZE) {
1845 buffer = (char *)__get_free_page(GFP_KERNEL);
1850 if (copy_from_user(buffer, buf, length)) {
1854 if (length < PAGE_SIZE) {
1855 buffer[length] = '\0';
1856 } else if (buffer[PAGE_SIZE-1]) {
1862 * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP_NAME/names
1863 * or echo "move NAME NEW_GROUP_NAME" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names"
1864 * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/names
1867 if (p[strlen(p) - 1] == '\n')
1868 p[strlen(p) - 1] = '\0';
1869 if (!strncasecmp("clear", p, 5)) {
1870 action = SCST_PROC_ACTION_CLEAR;
1871 } else if (!strncasecmp("add ", p, 4)) {
1873 action = SCST_PROC_ACTION_ADD;
1874 } else if (!strncasecmp("del ", p, 4)) {
1876 action = SCST_PROC_ACTION_DEL;
1877 } else if (!strncasecmp("move ", p, 5)) {
1879 action = SCST_PROC_ACTION_MOVE;
1881 PRINT_ERROR("Unknown action \"%s\"", p);
1887 case SCST_PROC_ACTION_ADD:
1888 case SCST_PROC_ACTION_DEL:
1889 case SCST_PROC_ACTION_MOVE:
1890 while (isspace(*p) && *p != '\0')
1893 while (!isspace(*pp) && *pp != '\0')
1898 while (isspace(*pp) && *pp != '\0')
1902 case SCST_PROC_ACTION_ADD:
1903 case SCST_PROC_ACTION_DEL:
1904 PRINT_ERROR("%s", "Too many "
1914 rc = scst_suspend_activity(true);
1918 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1920 goto out_free_resume;
1924 case SCST_PROC_ACTION_ADD:
1925 rc = scst_acg_add_name(acg, p);
1927 case SCST_PROC_ACTION_DEL:
1928 rc = scst_acg_remove_name(acg, p, true);
1930 case SCST_PROC_ACTION_MOVE:
1932 struct scst_acg *a, *new_acg = NULL;
1935 while (!isspace(*pp) && *pp != '\0')
1940 while (isspace(*pp) && *pp != '\0')
1943 PRINT_ERROR("%s", "Too many arguments");
1945 goto out_free_unlock;
1948 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1949 if (strcmp(a->acg_name, p) == 0) {
1950 TRACE_DBG("group (acg) %p %s found",
1956 if (new_acg == NULL) {
1957 PRINT_ERROR("Group %s not found", p);
1959 goto out_free_unlock;
1961 rc = scst_acg_remove_name(acg, name, false);
1963 goto out_free_unlock;
1964 rc = scst_acg_add_name(new_acg, name);
1967 case SCST_PROC_ACTION_CLEAR:
1968 list_for_each_entry_safe(n, nn, &acg->acn_list,
1970 __scst_acg_remove_acn(n);
1972 scst_check_reassign_sessions();
1977 mutex_unlock(&scst_mutex);
1980 scst_resume_activity();
1983 free_page((unsigned long)buffer);
1989 TRACE_EXIT_RES(res);
1993 static int scst_version_info_show(struct seq_file *seq, void *v)
1997 seq_printf(seq, "%s\n", SCST_VERSION_STRING);
1999 #ifdef CONFIG_SCST_STRICT_SERIALIZING
2000 seq_printf(seq, "Strict serializing enabled\n");
2003 #ifdef CONFIG_SCST_EXTRACHECKS
2004 seq_printf(seq, "EXTRACHECKS\n");
2007 #ifdef CONFIG_SCST_TRACING
2008 seq_printf(seq, "TRACING\n");
2011 #ifdef CONFIG_SCST_DEBUG
2012 seq_printf(seq, "DEBUG\n");
2015 #ifdef CONFIG_SCST_DEBUG_TM
2016 seq_printf(seq, "DEBUG_TM\n");
2019 #ifdef CONFIG_SCST_DEBUG_RETRY
2020 seq_printf(seq, "DEBUG_RETRY\n");
2023 #ifdef CONFIG_SCST_DEBUG_OOM
2024 seq_printf(seq, "DEBUG_OOM\n");
2027 #ifdef CONFIG_SCST_DEBUG_SN
2028 seq_printf(seq, "DEBUG_SN\n");
2031 #ifdef CONFIG_SCST_USE_EXPECTED_VALUES
2032 seq_printf(seq, "USE_EXPECTED_VALUES\n");
2035 #ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
2036 seq_printf(seq, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
2039 #ifdef CONFIG_SCST_STRICT_SECURITY
2040 seq_printf(seq, "SCST_STRICT_SECURITY\n");
2047 static struct scst_proc_data scst_version_proc_data = {
2048 SCST_DEF_RW_SEQ_OP(NULL)
2049 .show = scst_version_info_show,
2052 static int scst_help_info_show(struct seq_file *seq, void *v)
2056 seq_printf(seq, "%s\n", scst_proc_help_string);
2062 static struct scst_proc_data scst_help_proc_data = {
2063 SCST_DEF_RW_SEQ_OP(NULL)
2064 .show = scst_help_info_show,
2067 static int scst_dev_handler_type_info_show(struct seq_file *seq, void *v)
2069 struct scst_dev_type *dev_type = (struct scst_dev_type *)seq->private;
2073 seq_printf(seq, "%d - %s\n", dev_type->type,
2074 dev_type->type > (int)ARRAY_SIZE(scst_proc_dev_handler_type)
2075 ? "unknown" : scst_proc_dev_handler_type[dev_type->type]);
2081 static struct scst_proc_data scst_dev_handler_type_proc_data = {
2082 SCST_DEF_RW_SEQ_OP(NULL)
2083 .show = scst_dev_handler_type_info_show,
2086 static int scst_sessions_info_show(struct seq_file *seq, void *v)
2089 struct scst_acg *acg;
2090 struct scst_session *sess;
2094 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2099 seq_printf(seq, "%-20s %-45s %-35s %-15s\n",
2100 "Target name", "Initiator name",
2101 "Group name", "Command Count");
2103 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
2104 list_for_each_entry(sess, &acg->acg_sess_list,
2105 acg_sess_list_entry) {
2106 seq_printf(seq, "%-20s %-45s %-35s %-15d\n",
2107 sess->tgt->tgtt->name,
2108 sess->initiator_name,
2110 atomic_read(&sess->sess_cmd_count));
2114 mutex_unlock(&scst_mutex);
2117 TRACE_EXIT_RES(res);
2121 static struct scst_proc_data scst_sessions_proc_data = {
2122 SCST_DEF_RW_SEQ_OP(NULL)
2123 .show = scst_sessions_info_show,
2127 static struct scst_proc_data scst_sgv_proc_data = {
2128 SCST_DEF_RW_SEQ_OP(NULL)
2129 .show = sgv_procinfo_show,
2132 static int scst_groups_names_show(struct seq_file *seq, void *v)
2135 struct scst_acg *acg = (struct scst_acg *)seq->private;
2136 struct scst_acn *name;
2140 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2145 list_for_each_entry(name, &acg->acn_list, acn_list_entry) {
2146 seq_printf(seq, "%s\n", name->name);
2149 mutex_unlock(&scst_mutex);
2152 TRACE_EXIT_RES(res);
2156 static struct scst_proc_data scst_groups_names_proc_data = {
2157 SCST_DEF_RW_SEQ_OP(scst_proc_groups_names_write)
2158 .show = scst_groups_names_show,
2161 static int scst_groups_devices_show(struct seq_file *seq, void *v)
2164 struct scst_acg *acg = (struct scst_acg *)seq->private;
2165 struct scst_acg_dev *acg_dev;
2169 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2174 seq_printf(seq, "%-60s%-13s%s\n", "Device (host:ch:id:lun or name)",
2177 list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
2178 if (acg_dev->dev->virt_id == 0) {
2180 int size = sizeof(conv);
2182 memset(conv, 0, size);
2183 size = snprintf(conv, size, "%d:%d:%d:",
2184 acg_dev->dev->scsi_dev->host->host_no,
2185 acg_dev->dev->scsi_dev->channel,
2186 acg_dev->dev->scsi_dev->id);
2187 seq_printf(seq, "%s", conv);
2190 * For some reason the third string argument always
2191 * shown as NULL, so we have to split it on 2 calls.
2193 sprintf(conv, "%%-%dd%%-13d", 60 - size);
2194 size += seq_printf(seq, conv,
2195 acg_dev->dev->scsi_dev->lun,
2197 seq_printf(seq, "%s\n",
2198 acg_dev->rd_only ? "RO" : "");
2200 seq_printf(seq, "%-60s%-13lld%s\n",
2201 acg_dev->dev->virt_name,
2202 (long long unsigned int)acg_dev->lun,
2203 acg_dev->rd_only ? "RO" : "");
2206 mutex_unlock(&scst_mutex);
2209 TRACE_EXIT_RES(res);
2213 static struct scst_proc_data scst_groups_devices_proc_data = {
2214 SCST_DEF_RW_SEQ_OP(scst_proc_groups_devices_write)
2215 .show = scst_groups_devices_show,
2218 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2220 static int scst_proc_read_tlb(const struct scst_proc_log *tbl,
2221 struct seq_file *seq,
2222 unsigned long log_level, int *first)
2224 const struct scst_proc_log *t = tbl;
2228 if (log_level & t->val) {
2229 seq_printf(seq, "%s%s", *first ? "" : " | ", t->token);
2237 int scst_proc_log_entry_read(struct seq_file *seq, unsigned long log_level,
2238 const struct scst_proc_log *tbl)
2240 int res = 0, first = 1;
2244 scst_proc_read_tlb(scst_proc_trace_tbl, seq, log_level, &first);
2247 scst_proc_read_tlb(tbl, seq, log_level, &first);
2249 seq_printf(seq, "%s\n", first ? "none" : "");
2251 TRACE_EXIT_RES(res);
2254 EXPORT_SYMBOL(scst_proc_log_entry_read);
2256 static int log_info_show(struct seq_file *seq, void *v)
2262 if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
2267 res = scst_proc_log_entry_read(seq, trace_flag,
2268 scst_proc_local_trace_tbl);
2270 mutex_unlock(&scst_log_mutex);
2273 TRACE_EXIT_RES(res);
2277 static struct scst_proc_data scst_log_proc_data = {
2278 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_log)
2279 .show = log_info_show,
2285 static int scst_tgt_info_show(struct seq_file *seq, void *v)
2288 struct scst_device *dev;
2292 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2297 seq_printf(seq, "%-60s%s\n", "Device (host:ch:id:lun or name)",
2299 list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
2300 if (dev->virt_id == 0) {
2302 int size = sizeof(conv);
2303 size = snprintf(conv, size, "%d:%d:%d:",
2304 dev->scsi_dev->host->host_no,
2305 dev->scsi_dev->channel,
2307 seq_printf(seq, "%s", conv);
2308 sprintf(conv, "%%-%dd%%s\n", 60 - size);
2309 seq_printf(seq, conv, dev->scsi_dev->lun,
2310 dev->handler ? dev->handler->name : "-");
2312 seq_printf(seq, "%-60s%s\n",
2313 dev->virt_name, dev->handler->name);
2316 mutex_unlock(&scst_mutex);
2319 TRACE_EXIT_RES(res);
2323 static struct scst_proc_data scst_tgt_proc_data = {
2324 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write)
2325 .show = scst_tgt_info_show,
2328 static int scst_threads_info_show(struct seq_file *seq, void *v)
2332 seq_printf(seq, "%d\n", scst_global_threads_count());
2338 static struct scst_proc_data scst_threads_proc_data = {
2339 SCST_DEF_RW_SEQ_OP(scst_proc_threads_write)
2340 .show = scst_threads_info_show,
2343 static int scst_scsi_tgtinfo_show(struct seq_file *seq, void *v)
2345 struct scst_tgt *vtt = seq->private;
2350 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2355 if (vtt->tgtt->read_proc)
2356 res = vtt->tgtt->read_proc(seq, vtt);
2358 mutex_unlock(&scst_proc_mutex);
2360 TRACE_EXIT_RES(res);
2364 static struct scst_proc_data scst_scsi_tgt_proc_data = {
2365 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_write)
2366 .show = scst_scsi_tgtinfo_show,
2369 static int scst_dev_handler_info_show(struct seq_file *seq, void *v)
2371 struct scst_dev_type *dev_type = seq->private;
2376 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2381 if (dev_type->read_proc)
2382 res = dev_type->read_proc(seq, dev_type);
2384 mutex_unlock(&scst_proc_mutex);
2387 TRACE_EXIT_RES(res);
2391 static struct scst_proc_data scst_dev_handler_proc_data = {
2392 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_dev_handler_write)
2393 .show = scst_dev_handler_info_show,
2396 struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry *root,
2397 const char *name, struct scst_proc_data *pdata)
2399 struct proc_dir_entry *p = NULL;
2406 mode = S_IFREG | S_IRUGO | (pdata->seq_op.write ? S_IWUSR : 0);
2407 p = create_proc_entry(name, mode, root);
2409 PRINT_ERROR("Fail to create entry %s in /proc", name);
2411 p->proc_fops = &pdata->seq_op;
2412 p->data = pdata->data;
2419 EXPORT_SYMBOL(scst_create_proc_entry);
2421 int scst_single_seq_open(struct inode *inode, struct file *file)
2423 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
2424 struct scst_proc_data *pdata = container_of(PDE(inode)->proc_fops,
2425 struct scst_proc_data, seq_op);
2427 struct scst_proc_data *pdata = container_of(inode->i_fop,
2428 struct scst_proc_data, seq_op);
2430 return single_open(file, pdata->show, PDE(inode)->data);
2432 EXPORT_SYMBOL(scst_single_seq_open);