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_VALUE 9
84 #define SCST_PROC_ACTION_ASSIGN 10
85 #define SCST_PROC_ACTION_ADD_GROUP 11
86 #define SCST_PROC_ACTION_DEL_GROUP 12
87 #define SCST_PROC_ACTION_RENAME_GROUP 13
89 static struct proc_dir_entry *scst_proc_scsi_tgt;
90 static struct proc_dir_entry *scst_proc_groups_root;
92 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
93 static struct scst_proc_data scst_log_proc_data;
95 static struct scst_proc_log scst_proc_trace_tbl[] =
97 { TRACE_OUT_OF_MEM, "out_of_mem" },
98 { TRACE_MINOR, "minor" },
99 { TRACE_SG_OP, "sg" },
100 { TRACE_MEMORY, "mem" },
101 { TRACE_BUFF, "buff" },
102 { TRACE_ENTRYEXIT, "entryexit" },
103 { TRACE_PID, "pid" },
104 { TRACE_LINE, "line" },
105 { TRACE_FUNCTION, "function" },
106 { TRACE_DEBUG, "debug" },
107 { TRACE_SPECIAL, "special" },
108 { TRACE_SCSI, "scsi" },
109 { TRACE_MGMT, "mgmt" },
110 { TRACE_MGMT_MINOR, "mgmt_minor" },
111 { TRACE_MGMT_DEBUG, "mgmt_dbg" },
115 static struct scst_proc_log scst_proc_local_trace_tbl[] =
117 { TRACE_RTRY, "retry" },
118 { TRACE_SCSI_SERIALIZING, "scsi_serializing" },
119 { TRACE_RCV_BOT, "recv_bot" },
120 { TRACE_SND_BOT, "send_bot" },
121 { TRACE_RCV_TOP, "recv_top" },
122 { TRACE_SND_TOP, "send_top" },
127 static char *scst_proc_help_string =
128 " echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
130 " echo \"add_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
131 " echo \"del_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
132 " echo \"rename_group OLD_NAME NEW_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
134 " echo \"add|del H:C:I:L lun [READ_ONLY]\""
135 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
136 " echo \"add|del V_NAME lun [READ_ONLY]\""
137 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
138 " echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
140 " echo \"add|del NAME\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n"
141 " echo \"move NAME NEW_GROUP_NAME\" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names\n"
142 " echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n"
144 " echo \"DEC|0xHEX|0OCT\" >/proc/scsi_tgt/threads\n"
145 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
147 " echo \"all|none|default\" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
148 " echo \"value DEC|0xHEX|0OCT\""
149 " >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
150 " echo \"set|add|del TOKEN\""
151 " >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
152 " where TOKEN is one of [debug,function,line,pid,entryexit,\n"
153 " buff,mem,sg,out_of_mem,special,scsi,mgmt,minor]\n"
154 " Additionally for /proc/scsi_tgt/trace_level there are these TOKENs\n"
155 " [scsi_serializing,retry,recv_bot,send_bot,recv_top,send_top]\n"
159 static char *scst_proc_dev_handler_type[] =
161 "Direct-access device (e.g., magnetic disk)",
162 "Sequential-access device (e.g., magnetic tape)",
165 "Write-once device (e.g., some optical disks)",
167 "Scanner device (obsolete)",
168 "Optical memory device (e.g., some optical disks)",
169 "Medium changer device (e.g., jukeboxes)",
170 "Communications device (obsolete)",
171 "Defined by ASC IT8 (Graphic arts pre-press devices)",
172 "Defined by ASC IT8 (Graphic arts pre-press devices)",
173 "Storage array controller device (e.g., RAID)",
174 "Enclosure services device",
175 "Simplified direct-access device (e.g., magnetic disk)",
176 "Optical card reader/writer device"
179 static DEFINE_MUTEX(scst_proc_mutex);
181 #include <linux/ctype.h>
183 #if !defined(CONFIG_PPC) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3)
185 * If strcasecmp() and strncasecmp() have already been declared in
186 * <linux/string.h>, do not redefine these functions. Declarations for these
187 * functions are present in the <linux/string.h> header of the following
189 * - The PPC kernel headers for all kernel versions supported by SCST.
190 * - Kernel version 2.6.22 and later for all architectures.
191 * - RHEL 5.3 and later.
193 * Notes about the above preprocessor statement:
194 * - We can't use RHEL_RELEASE_CODE(5, 3) because it would trigger an error on
195 * non-RHEL/CentOS systems -- this expression would expand to "(5,3)".
196 * - There is no space between the minus sign and the zero in the expression
197 * "RHEL_RELEASE_CODE -0" such that it expands to a syntactically valid
198 * expression on non-RHEL/CentOS systems ("-0").
199 * - The above statement has been put on one long line because as of r800
200 * scripts/specialize-patch does not yet handle multi-line preprocessor
201 * statements correctly.
204 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
205 static int strcasecmp(const char *s1, const char *s2)
211 } while (c1 == c2 && c1 != 0);
216 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
217 static int strncasecmp(const char *s1, const char *s2, int n)
219 static int strncasecmp(const char *s1, const char *s2, size_t n)
226 } while ((--n > 0) && c1 == c2 && c1 != 0);
230 #endif /* !CONFIG_PPC && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) */
232 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
234 static DEFINE_MUTEX(scst_log_mutex);
236 int scst_proc_log_entry_write(struct file *file, const char __user *buf,
237 unsigned long length, unsigned long *log_level,
238 unsigned long default_level, const struct scst_proc_log *tbl)
242 unsigned long level = 0, oldlevel;
243 char *buffer, *p, *e;
244 const struct scst_proc_log *t;
245 char *data = (char *)PDE(file->f_dentry->d_inode)->data;
249 if (length > SCST_PROC_BLOCK_SIZE) {
257 buffer = (char *)__get_free_page(GFP_KERNEL);
262 if (copy_from_user(buffer, buf, length)) {
266 if (length < PAGE_SIZE) {
267 buffer[length] = '\0';
268 } else if (buffer[PAGE_SIZE-1]) {
275 * echo "all|none|default" >/proc/scsi_tgt/trace_level
276 * echo "value DEC|0xHEX|0OCT" >/proc/scsi_tgt/trace_level
277 * echo "set|add|clear|del TOKEN" >/proc/scsi_tgt/trace_level
278 * where TOKEN is one of [debug,function,line,pid,entryexit,
279 * buff,mem,sg,out_of_mem,retry,
280 * scsi_serializing,special,scsi,mgmt,minor,...]
283 if (!strncasecmp("all", p, 3)) {
284 action = SCST_PROC_ACTION_ALL;
285 } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) {
286 action = SCST_PROC_ACTION_NONE;
287 } else if (!strncasecmp("default", p, 7)) {
288 action = SCST_PROC_ACTION_DEFAULT;
289 } else if (!strncasecmp("set ", p, 4)) {
291 action = SCST_PROC_ACTION_SET;
292 } else if (!strncasecmp("add ", p, 4)) {
294 action = SCST_PROC_ACTION_ADD;
295 } else if (!strncasecmp("del ", p, 4)) {
297 action = SCST_PROC_ACTION_DEL;
298 } else if (!strncasecmp("value ", p, 6)) {
300 action = SCST_PROC_ACTION_VALUE;
302 if (p[strlen(p) - 1] == '\n')
303 p[strlen(p) - 1] = '\0';
304 PRINT_ERROR("Unknown action \"%s\"", p);
310 case SCST_PROC_ACTION_ALL:
313 case SCST_PROC_ACTION_DEFAULT:
314 level = default_level;
316 case SCST_PROC_ACTION_NONE:
319 case SCST_PROC_ACTION_SET:
320 case SCST_PROC_ACTION_ADD:
321 case SCST_PROC_ACTION_DEL:
322 while (isspace(*p) && *p != '\0')
325 while (!isspace(*e) && *e != '\0')
331 if (!strcasecmp(p, t->token)) {
339 t = scst_proc_trace_tbl;
341 if (!strcasecmp(p, t->token)) {
349 PRINT_ERROR("Unknown token \"%s\"", p);
354 case SCST_PROC_ACTION_VALUE:
355 while (isspace(*p) && *p != '\0')
357 level = simple_strtoul(p, NULL, 0);
361 oldlevel = *log_level;
364 case SCST_PROC_ACTION_ADD:
367 case SCST_PROC_ACTION_DEL:
368 *log_level &= ~level;
375 PRINT_INFO("Changed trace level for \"%s\": "
376 "old 0x%08lx, new 0x%08lx",
377 (char *)data, oldlevel, *log_level);
380 free_page((unsigned long)buffer);
385 EXPORT_SYMBOL(scst_proc_log_entry_write);
387 static ssize_t scst_proc_scsi_tgt_gen_write_log(struct file *file,
388 const char __user *buf,
389 size_t length, loff_t *off)
395 if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
400 res = scst_proc_log_entry_write(file, buf, length,
401 &trace_flag, SCST_DEFAULT_LOG_FLAGS,
402 scst_proc_local_trace_tbl);
404 mutex_unlock(&scst_log_mutex);
411 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
413 #ifdef CONFIG_SCST_MEASURE_LATENCY
415 static int lat_info_show(struct seq_file *seq, void *v)
418 struct scst_acg *acg;
419 struct scst_session *sess;
423 if (mutex_lock_interruptible(&scst_mutex) != 0) {
428 seq_printf(seq, "%-20s %-45s %-15s %15s\n",
432 "Processing latency (ns)");
434 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
435 list_for_each_entry(sess, &acg->acg_sess_list,
436 acg_sess_list_entry) {
437 unsigned long proc_lat = 0, scst_lat = 0;
438 uint64_t proc_time, scst_time;
439 unsigned int processed_cmds;
441 spin_lock_bh(&sess->meas_lock);
442 proc_time = sess->processing_time;
443 scst_time = sess->scst_time;
444 processed_cmds = sess->processed_cmds;
445 spin_unlock_bh(&sess->meas_lock);
447 TRACE_DBG("sess %p, scst_time %lld, proc_time %lld, "
448 "processed_cmds %d", sess, scst_time,
449 proc_time, processed_cmds);
451 #if BITS_PER_LONG == 32
452 /* Unfortunately, do_div() doesn't work too well */
453 while (((proc_time & 0xFFFFFFFF00000000LL) != 0) ||
454 ((scst_time & 0xFFFFFFFF00000000LL) != 0)) {
455 TRACE_DBG("%s", "Gathered time too big");
458 processed_cmds >>= 1;
462 if (sess->processed_cmds != 0) {
463 proc_lat = (unsigned long)proc_time /
465 scst_lat = (unsigned long)scst_time /
469 seq_printf(seq, "%-20s %-45s %-15ld %-15ld\n",
470 sess->tgt->tgtt->name,
471 sess->initiator_name,
476 mutex_unlock(&scst_mutex);
483 static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file,
484 const char __user *buf,
485 size_t length, loff_t *off)
488 struct scst_acg *acg;
489 struct scst_session *sess;
493 if (mutex_lock_interruptible(&scst_mutex) != 0) {
498 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
499 list_for_each_entry(sess, &acg->acg_sess_list,
500 acg_sess_list_entry) {
501 PRINT_INFO("Zeroing latency statistics for initiator"
503 sess->initiator_name);
504 spin_lock_bh(&sess->meas_lock);
505 sess->processing_time = 0;
507 sess->processed_cmds = 0;
508 spin_unlock_bh(&sess->meas_lock);
512 mutex_unlock(&scst_mutex);
519 static struct scst_proc_data scst_lat_proc_data = {
520 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_lat)
521 .show = lat_info_show,
525 #endif /* CONFIG_SCST_MEASURE_LATENCY */
527 static int __init scst_proc_init_module_log(void)
530 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) || \
531 defined(CONFIG_SCST_MEASURE_LATENCY)
532 struct proc_dir_entry *generic;
537 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
538 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
539 SCST_PROC_LOG_ENTRY_NAME,
540 &scst_log_proc_data);
542 PRINT_ERROR("cannot init /proc/%s/%s",
543 SCST_PROC_ENTRY_NAME, SCST_PROC_LOG_ENTRY_NAME);
548 #ifdef CONFIG_SCST_MEASURE_LATENCY
550 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
551 SCST_PROC_LAT_ENTRY_NAME,
552 &scst_lat_proc_data);
554 PRINT_ERROR("cannot init /proc/%s/%s",
555 SCST_PROC_ENTRY_NAME,
556 SCST_PROC_LAT_ENTRY_NAME);
566 static void scst_proc_cleanup_module_log(void)
570 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
571 remove_proc_entry(SCST_PROC_LOG_ENTRY_NAME, scst_proc_scsi_tgt);
574 #ifdef CONFIG_SCST_MEASURE_LATENCY
575 remove_proc_entry(SCST_PROC_LAT_ENTRY_NAME, scst_proc_scsi_tgt);
582 static int scst_proc_group_add_tree(struct scst_acg *acg, const char *name)
585 struct proc_dir_entry *generic;
589 acg->acg_proc_root = proc_mkdir(name, scst_proc_groups_root);
590 if (acg->acg_proc_root == NULL) {
591 PRINT_ERROR("Not enough memory to register %s entry in "
592 "/proc/%s/%s", name, SCST_PROC_ENTRY_NAME,
593 SCST_PROC_GROUPS_ENTRY_NAME);
597 scst_groups_devices_proc_data.data = acg;
598 generic = scst_create_proc_entry(acg->acg_proc_root,
599 SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
600 &scst_groups_devices_proc_data);
602 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
603 SCST_PROC_ENTRY_NAME,
604 SCST_PROC_GROUPS_ENTRY_NAME,
605 name, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME);
610 scst_groups_names_proc_data.data = acg;
611 generic = scst_create_proc_entry(acg->acg_proc_root,
612 SCST_PROC_GROUPS_USERS_ENTRY_NAME,
613 &scst_groups_names_proc_data);
615 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
616 SCST_PROC_ENTRY_NAME,
617 SCST_PROC_GROUPS_ENTRY_NAME,
618 name, SCST_PROC_GROUPS_USERS_ENTRY_NAME);
628 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
632 remove_proc_entry(name, scst_proc_groups_root);
636 static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
641 remove_proc_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME, acg_proc_root);
642 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
644 remove_proc_entry(name, scst_proc_groups_root);
650 /* The activity supposed to be suspended and scst_mutex held */
651 static int scst_proc_group_add(const char *p)
653 int res = 0, len = strlen(p) + 1;
654 struct scst_acg *acg;
659 name = kmalloc(len, GFP_KERNEL);
661 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of name failed");
664 strncpy(name, p, len);
666 acg = scst_alloc_add_acg(name);
668 PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", name);
672 res = scst_proc_group_add_tree(acg, p);
681 scst_proc_del_free_acg(acg, 0);
691 /* The activity supposed to be suspended and scst_mutex held */
692 static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc)
695 struct proc_dir_entry *acg_proc_root = acg->acg_proc_root;
700 if (acg != scst_default_acg) {
701 name = acg->acg_name;
702 res = scst_destroy_acg(acg);
705 scst_proc_del_acg_tree(acg_proc_root, name);
714 /* The activity supposed to be suspended and scst_mutex held */
715 static int scst_proc_rename_acg(struct scst_acg *acg, const char *new_name)
717 int res = 0, len = strlen(new_name) + 1;
719 struct proc_dir_entry *old_acg_proc_root = acg->acg_proc_root;
723 name = kmalloc(len, GFP_KERNEL);
725 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of new name failed");
728 strncpy(name, new_name, len);
730 res = scst_proc_group_add_tree(acg, new_name);
734 scst_proc_del_acg_tree(old_acg_proc_root, acg->acg_name);
736 kfree(acg->acg_name);
737 acg->acg_name = name;
739 scst_check_reassign_sessions();
753 static int __init scst_proc_init_groups(void)
759 /* create the proc directory entry for the device */
760 scst_proc_groups_root = proc_mkdir(SCST_PROC_GROUPS_ENTRY_NAME,
762 if (scst_proc_groups_root == NULL) {
763 PRINT_ERROR("Not enough memory to register %s entry in "
764 "/proc/%s", SCST_PROC_GROUPS_ENTRY_NAME,
765 SCST_PROC_ENTRY_NAME);
769 res = scst_proc_group_add_tree(scst_default_acg,
770 SCST_DEFAULT_ACG_NAME);
779 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
786 static void scst_proc_cleanup_groups(void)
788 struct scst_acg *acg_tmp, *acg;
792 /* remove all groups (dir & entries) */
793 list_for_each_entry_safe(acg, acg_tmp, &scst_acg_list,
794 scst_acg_list_entry) {
795 scst_proc_del_free_acg(acg, 1);
798 scst_proc_del_acg_tree(scst_default_acg->acg_proc_root,
799 SCST_DEFAULT_ACG_NAME);
800 TRACE_DBG("remove_proc_entry(%s, %p)",
801 SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
802 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
807 static int __init scst_proc_init_sgv(void)
810 struct proc_dir_entry *pr;
814 pr = scst_create_proc_entry(scst_proc_scsi_tgt, "sgv",
815 &scst_sgv_proc_data);
817 PRINT_ERROR("%s", "cannot create sgv /proc entry");
825 static void __exit scst_proc_cleanup_sgv(void)
828 remove_proc_entry("sgv", scst_proc_scsi_tgt);
832 int __init scst_proc_init_module(void)
835 struct proc_dir_entry *generic;
839 scst_proc_scsi_tgt = proc_mkdir(SCST_PROC_ENTRY_NAME, NULL);
840 if (!scst_proc_scsi_tgt) {
841 PRINT_ERROR("cannot init /proc/%s", SCST_PROC_ENTRY_NAME);
845 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
846 SCST_PROC_ENTRY_NAME,
847 &scst_tgt_proc_data);
849 PRINT_ERROR("cannot init /proc/%s/%s",
850 SCST_PROC_ENTRY_NAME, SCST_PROC_ENTRY_NAME);
854 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
855 SCST_PROC_VERSION_NAME,
856 &scst_version_proc_data);
858 PRINT_ERROR("cannot init /proc/%s/%s",
859 SCST_PROC_ENTRY_NAME, SCST_PROC_VERSION_NAME);
863 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
864 SCST_PROC_SESSIONS_NAME,
865 &scst_sessions_proc_data);
867 PRINT_ERROR("cannot init /proc/%s/%s",
868 SCST_PROC_ENTRY_NAME, SCST_PROC_SESSIONS_NAME);
872 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
874 &scst_help_proc_data);
876 PRINT_ERROR("cannot init /proc/%s/%s",
877 SCST_PROC_ENTRY_NAME, SCST_PROC_HELP_NAME);
881 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
882 SCST_PROC_THREADS_NAME,
883 &scst_threads_proc_data);
885 PRINT_ERROR("cannot init /proc/%s/%s",
886 SCST_PROC_ENTRY_NAME, SCST_PROC_THREADS_NAME);
890 if (scst_proc_init_module_log() < 0)
893 if (scst_proc_init_groups() < 0)
896 if (scst_proc_init_sgv() < 0)
904 scst_proc_cleanup_groups();
907 scst_proc_cleanup_module_log();
910 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
913 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
916 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
919 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
922 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
925 remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
932 void __exit scst_proc_cleanup_module(void)
936 /* We may not bother about locks here */
937 scst_proc_cleanup_sgv();
938 scst_proc_cleanup_groups();
939 scst_proc_cleanup_module_log();
940 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
941 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
942 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
943 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
944 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
945 remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
950 static ssize_t scst_proc_threads_write(struct file *file,
951 const char __user *buf,
952 size_t length, loff_t *off)
955 int oldtn, newtn, delta;
960 if (length > SCST_PROC_BLOCK_SIZE) {
968 buffer = (char *)__get_free_page(GFP_KERNEL);
973 if (copy_from_user(buffer, buf, length)) {
977 if (length < PAGE_SIZE) {
978 buffer[length] = '\0';
979 } else if (buffer[PAGE_SIZE-1]) {
984 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
989 mutex_lock(&scst_global_threads_mutex);
991 oldtn = scst_nr_global_threads;
992 newtn = simple_strtoul(buffer, NULL, 0);
994 PRINT_ERROR("Illegal threads num value %d", newtn);
996 goto out_up_thr_free;
998 delta = newtn - oldtn;
1000 __scst_del_global_threads(-delta);
1002 __scst_add_global_threads(delta);
1004 PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
1007 mutex_unlock(&scst_global_threads_mutex);
1009 mutex_unlock(&scst_proc_mutex);
1012 free_page((unsigned long)buffer);
1014 TRACE_EXIT_RES(res);
1018 int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt)
1024 /* create the proc directory entry for the device */
1025 vtt->proc_tgt_root = proc_mkdir(vtt->name, scst_proc_scsi_tgt);
1026 if (vtt->proc_tgt_root == NULL) {
1027 PRINT_ERROR("Not enough memory to register SCSI target %s "
1028 "in /proc/%s", vtt->name, SCST_PROC_ENTRY_NAME);
1033 TRACE_EXIT_RES(res);
1041 void scst_cleanup_proc_target_dir_entries(struct scst_tgt_template *vtt)
1045 remove_proc_entry(vtt->name, scst_proc_scsi_tgt);
1051 /* Called under scst_mutex */
1052 int scst_build_proc_target_entries(struct scst_tgt *vtt)
1055 struct proc_dir_entry *p;
1060 if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1061 /* create the proc file entry for the device */
1062 scnprintf(name, sizeof(name), "%d", vtt->tgtt->proc_dev_num);
1063 scst_scsi_tgt_proc_data.data = (void *)vtt;
1064 p = scst_create_proc_entry(vtt->tgtt->proc_tgt_root,
1066 &scst_scsi_tgt_proc_data);
1068 PRINT_ERROR("Not enough memory to register SCSI "
1069 "target entry %s in /proc/%s/%s", name,
1070 SCST_PROC_ENTRY_NAME, vtt->tgtt->name);
1074 vtt->proc_num = vtt->tgtt->proc_dev_num;
1075 vtt->tgtt->proc_dev_num++;
1079 TRACE_EXIT_RES(res);
1083 void scst_cleanup_proc_target_entries(struct scst_tgt *vtt)
1089 if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1090 scnprintf(name, sizeof(name), "%d", vtt->proc_num);
1091 remove_proc_entry(name, vtt->tgtt->proc_tgt_root);
1098 static ssize_t scst_proc_scsi_tgt_write(struct file *file,
1099 const char __user *buf,
1100 size_t length, loff_t *off)
1102 struct scst_tgt *vtt =
1103 (struct scst_tgt *)PDE(file->f_dentry->d_inode)->data;
1111 if (vtt->tgtt->write_proc == NULL) {
1116 if (length > SCST_PROC_BLOCK_SIZE) {
1124 buffer = (char *)__get_free_page(GFP_KERNEL);
1129 if (copy_from_user(buffer, buf, length)) {
1133 if (length < PAGE_SIZE) {
1134 buffer[length] = '\0';
1135 } else if (buffer[PAGE_SIZE-1]) {
1140 TRACE_BUFFER("Buffer", buffer, length);
1142 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1147 res = vtt->tgtt->write_proc(buffer, &start, 0, length, &eof, vtt);
1149 mutex_unlock(&scst_proc_mutex);
1152 free_page((unsigned long)buffer);
1154 TRACE_EXIT_RES(res);
1158 int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1161 struct proc_dir_entry *p;
1165 sBUG_ON(dev_type->proc_dev_type_root);
1167 /* create the proc directory entry for the dev type handler */
1168 dev_type->proc_dev_type_root = proc_mkdir(dev_type->name,
1169 scst_proc_scsi_tgt);
1170 if (dev_type->proc_dev_type_root == NULL) {
1171 PRINT_ERROR("Not enough memory to register dev handler dir "
1172 "%s in /proc/%s", dev_type->name, SCST_PROC_ENTRY_NAME);
1176 scst_dev_handler_type_proc_data.data = dev_type;
1177 if (dev_type->type >= 0) {
1178 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1179 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1180 &scst_dev_handler_type_proc_data);
1182 PRINT_ERROR("Not enough memory to register dev "
1183 "handler entry %s in /proc/%s/%s",
1184 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1185 SCST_PROC_ENTRY_NAME, dev_type->name);
1190 if (dev_type->read_proc || dev_type->write_proc) {
1191 /* create the proc file entry for the dev type handler */
1192 scst_dev_handler_proc_data.data = (void *)dev_type;
1193 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1195 &scst_dev_handler_proc_data);
1197 PRINT_ERROR("Not enough memory to register dev "
1198 "handler entry %s in /proc/%s/%s", dev_type->name,
1199 SCST_PROC_ENTRY_NAME, dev_type->name);
1205 TRACE_EXIT_RES(res);
1209 if (dev_type->type >= 0)
1210 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1211 dev_type->proc_dev_type_root);
1214 remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1221 void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1225 sBUG_ON(dev_type->proc_dev_type_root == NULL);
1227 if (dev_type->type >= 0) {
1228 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1229 dev_type->proc_dev_type_root);
1231 if (dev_type->read_proc || dev_type->write_proc)
1232 remove_proc_entry(dev_type->name, dev_type->proc_dev_type_root);
1233 remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1234 dev_type->proc_dev_type_root = NULL;
1240 static ssize_t scst_proc_scsi_dev_handler_write(struct file *file,
1241 const char __user *buf,
1242 size_t length, loff_t *off)
1244 struct scst_dev_type *dev_type =
1245 (struct scst_dev_type *)PDE(file->f_dentry->d_inode)->data;
1253 if (dev_type->write_proc == NULL) {
1258 if (length > SCST_PROC_BLOCK_SIZE) {
1267 buffer = (char *)__get_free_page(GFP_KERNEL);
1273 if (copy_from_user(buffer, buf, length)) {
1277 if (length < PAGE_SIZE) {
1278 buffer[length] = '\0';
1279 } else if (buffer[PAGE_SIZE-1]) {
1284 TRACE_BUFFER("Buffer", buffer, length);
1286 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1291 res = dev_type->write_proc(buffer, &start, 0, length, &eof, dev_type);
1293 mutex_unlock(&scst_proc_mutex);
1296 free_page((unsigned long)buffer);
1299 TRACE_EXIT_RES(res);
1303 static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file,
1304 const char __user *buf,
1305 size_t length, loff_t *off)
1307 int res, rc = 0, action;
1308 char *buffer, *p, *pp;
1309 struct scst_acg *a, *acg = NULL;
1313 if (length > SCST_PROC_BLOCK_SIZE) {
1321 buffer = (char *)__get_free_page(GFP_KERNEL);
1326 if (copy_from_user(buffer, buf, length)) {
1330 if (length < PAGE_SIZE) {
1331 buffer[length] = '\0';
1332 } else if (buffer[PAGE_SIZE-1]) {
1338 * Usage: echo "add_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1339 * or echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1340 * or echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt"
1341 * or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt
1344 if (p[strlen(p) - 1] == '\n')
1345 p[strlen(p) - 1] = '\0';
1346 if (!strncasecmp("assign ", p, 7)) {
1348 action = SCST_PROC_ACTION_ASSIGN;
1349 } else if (!strncasecmp("add_group ", p, 10)) {
1351 action = SCST_PROC_ACTION_ADD_GROUP;
1352 } else if (!strncasecmp("del_group ", p, 10)) {
1354 action = SCST_PROC_ACTION_DEL_GROUP;
1355 } else if (!strncasecmp("rename_group ", p, 13)) {
1357 action = SCST_PROC_ACTION_RENAME_GROUP;
1359 PRINT_ERROR("Unknown action \"%s\"", p);
1364 res = scst_suspend_activity(true);
1368 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1370 goto out_free_resume;
1376 case SCST_PROC_ACTION_ADD_GROUP:
1377 case SCST_PROC_ACTION_DEL_GROUP:
1378 case SCST_PROC_ACTION_RENAME_GROUP:
1380 while (!isspace(*pp) && *pp != '\0')
1385 while (isspace(*pp) && *pp != '\0')
1389 case SCST_PROC_ACTION_ADD_GROUP:
1390 case SCST_PROC_ACTION_DEL_GROUP:
1391 PRINT_ERROR("%s", "Too many "
1399 if (strcmp(p, SCST_DEFAULT_ACG_NAME) == 0) {
1400 PRINT_ERROR("Attempt to add/delete/rename predefined "
1406 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1407 if (strcmp(a->acg_name, p) == 0) {
1408 TRACE_DBG("group (acg) %p %s found",
1416 case SCST_PROC_ACTION_ADD_GROUP:
1418 PRINT_ERROR("acg name %s exist", p);
1422 rc = scst_proc_group_add(p);
1424 case SCST_PROC_ACTION_DEL_GROUP:
1426 PRINT_ERROR("acg name %s not found", p);
1430 rc = scst_proc_del_free_acg(acg, 1);
1432 case SCST_PROC_ACTION_RENAME_GROUP:
1434 PRINT_ERROR("acg name %s not found", p);
1440 while (!isspace(*pp) && *pp != '\0')
1445 while (isspace(*pp) && *pp != '\0')
1448 PRINT_ERROR("%s", "Too many arguments");
1453 rc = scst_proc_rename_acg(acg, p);
1457 case SCST_PROC_ACTION_ASSIGN:
1458 rc = scst_proc_assign_handler(p);
1466 mutex_unlock(&scst_mutex);
1469 scst_resume_activity();
1472 free_page((unsigned long)buffer);
1475 TRACE_EXIT_RES(res);
1479 /* The activity supposed to be suspended and scst_mutex held */
1480 static int scst_proc_assign_handler(char *buf)
1483 char *p = buf, *e, *ee;
1484 unsigned long host, channel = 0, id = 0, lun = 0;
1485 struct scst_device *d, *dev = NULL;
1486 struct scst_dev_type *dt, *handler = NULL;
1490 while (isspace(*p) && *p != '\0')
1493 host = simple_strtoul(p, &p, 0);
1494 if ((host == ULONG_MAX) || (*p != ':'))
1497 channel = simple_strtoul(p, &p, 0);
1498 if ((channel == ULONG_MAX) || (*p != ':'))
1501 id = simple_strtoul(p, &p, 0);
1502 if ((channel == ULONG_MAX) || (*p != ':'))
1505 lun = simple_strtoul(p, &p, 0);
1506 if (lun == ULONG_MAX)
1511 while (isspace(*e) && *e != '\0')
1514 while (!isspace(*ee) && *ee != '\0')
1518 TRACE_DBG("Dev %ld:%ld:%ld:%ld, handler %s", host, channel, id, lun, e);
1520 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1521 if ((d->virt_id == 0) &&
1522 d->scsi_dev->host->host_no == host &&
1523 d->scsi_dev->channel == channel &&
1524 d->scsi_dev->id == id &&
1525 d->scsi_dev->lun == lun) {
1527 TRACE_DBG("Dev %p (%ld:%ld:%ld:%ld) found",
1528 dev, host, channel, id, lun);
1534 PRINT_ERROR("Device %ld:%ld:%ld:%ld not found",
1535 host, channel, id, lun);
1540 list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
1541 if (!strcmp(dt->name, e)) {
1543 TRACE_DBG("Dev handler %p with name %s found",
1549 if (handler == NULL) {
1550 PRINT_ERROR("Handler %s not found", e);
1555 if (dev->scsi_dev->type != handler->type) {
1556 PRINT_ERROR("Type %d of device %s differs from type "
1557 "%d of dev handler %s", dev->type,
1558 dev->handler->name, handler->type, handler->name);
1563 res = scst_assign_dev_handler(dev, handler);
1566 TRACE_EXIT_RES(res);
1570 PRINT_ERROR("Syntax error on %s", p);
1575 static ssize_t scst_proc_groups_devices_write(struct file *file,
1576 const char __user *buf,
1577 size_t length, loff_t *off)
1579 int res, action, virt = 0, rc, read_only = 0;
1580 char *buffer, *p, *e = NULL;
1581 unsigned int host, channel = 0, id = 0, lun = 0, virt_lun;
1582 struct scst_acg *acg =
1583 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1584 struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
1585 struct scst_device *d, *dev = NULL;
1589 if (length > SCST_PROC_BLOCK_SIZE) {
1597 buffer = (char *)__get_free_page(GFP_KERNEL);
1602 if (copy_from_user(buffer, buf, length)) {
1606 if (length < PAGE_SIZE) {
1607 buffer[length] = '\0';
1608 } else if (buffer[PAGE_SIZE-1]) {
1614 * Usage: echo "add|del H:C:I:L lun [READ_ONLY]" \
1615 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1616 * or echo "add|del V_NAME lun [READ_ONLY]" \
1617 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1618 * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/devices
1621 if (p[strlen(p) - 1] == '\n')
1622 p[strlen(p) - 1] = '\0';
1623 if (!strncasecmp("clear", p, 5)) {
1624 action = SCST_PROC_ACTION_CLEAR;
1625 } else if (!strncasecmp("add ", p, 4)) {
1627 action = SCST_PROC_ACTION_ADD;
1628 } else if (!strncasecmp("del ", p, 4)) {
1630 action = SCST_PROC_ACTION_DEL;
1632 PRINT_ERROR("Unknown action \"%s\"", p);
1637 res = scst_suspend_activity(true);
1641 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1643 goto out_free_resume;
1649 case SCST_PROC_ACTION_ADD:
1650 case SCST_PROC_ACTION_DEL:
1651 while (isspace(*p) && *p != '\0')
1654 host = simple_strtoul(p, &p, 0);
1656 channel = simple_strtoul(p + 1, &p, 0);
1657 id = simple_strtoul(p + 1, &p, 0);
1658 lun = simple_strtoul(p + 1, &p, 0);
1662 p = e; /* restore p */
1663 while (!isspace(*e) && *e != '\0')
1668 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1670 if (d->virt_id && !strcmp(d->virt_name, p)) {
1672 TRACE_DBG("Virt device %p (%s) found",
1678 d->scsi_dev->host->host_no == host &&
1679 d->scsi_dev->channel == channel &&
1680 d->scsi_dev->id == id &&
1681 d->scsi_dev->lun == lun) {
1683 TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
1684 dev, host, channel, id, lun);
1691 PRINT_ERROR("Virt device %s not found", p);
1693 PRINT_ERROR("Device %d:%d:%d:%d not found",
1694 host, channel, id, lun);
1702 /* ToDo: create separate functions */
1705 case SCST_PROC_ACTION_ADD:
1707 while (isspace(*e) && *e != '\0')
1709 virt_lun = simple_strtoul(e, &e, 0);
1711 while (isspace(*e) && *e != '\0')
1715 if (!strncasecmp("READ_ONLY", e, 9))
1718 PRINT_ERROR("Unknown option \"%s\"", e);
1724 list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
1725 acg_dev_list_entry) {
1726 if (acg_dev_tmp->lun == virt_lun) {
1727 acg_dev = acg_dev_tmp;
1732 acg_dev = acg_dev_tmp;
1733 PRINT_ERROR("virt lun %d already exists in group %s",
1734 virt_lun, acg->acg_name);
1738 rc = scst_acg_add_dev(acg, dev, virt_lun, read_only);
1740 PRINT_ERROR("scst_acg_add_dev() returned %d", rc);
1744 case SCST_PROC_ACTION_DEL:
1745 rc = scst_acg_remove_dev(acg, dev);
1747 PRINT_ERROR("scst_acg_remove_dev() returned %d", rc);
1751 case SCST_PROC_ACTION_CLEAR:
1752 list_for_each_entry_safe(acg_dev, acg_dev_tmp,
1754 acg_dev_list_entry) {
1755 rc = scst_acg_remove_dev(acg, acg_dev->dev);
1757 PRINT_ERROR("scst_acg_remove_dev() "
1766 mutex_unlock(&scst_mutex);
1769 scst_resume_activity();
1772 free_page((unsigned long)buffer);
1775 TRACE_EXIT_RES(res);
1779 static ssize_t scst_proc_groups_names_write(struct file *file,
1780 const char __user *buf,
1781 size_t length, loff_t *off)
1783 int res = length, rc = 0, action;
1784 char *buffer, *p, *pp = NULL;
1785 struct scst_acg *acg =
1786 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1787 struct scst_acn *n, *nn;
1791 if (length > SCST_PROC_BLOCK_SIZE) {
1799 buffer = (char *)__get_free_page(GFP_KERNEL);
1804 if (copy_from_user(buffer, buf, length)) {
1808 if (length < PAGE_SIZE) {
1809 buffer[length] = '\0';
1810 } else if (buffer[PAGE_SIZE-1]) {
1816 * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP_NAME/names
1817 * or echo "move NAME NEW_GROUP_NAME" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names"
1818 * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/names
1821 if (p[strlen(p) - 1] == '\n')
1822 p[strlen(p) - 1] = '\0';
1823 if (!strncasecmp("clear", p, 5)) {
1824 action = SCST_PROC_ACTION_CLEAR;
1825 } else if (!strncasecmp("add ", p, 4)) {
1827 action = SCST_PROC_ACTION_ADD;
1828 } else if (!strncasecmp("del ", p, 4)) {
1830 action = SCST_PROC_ACTION_DEL;
1831 } else if (!strncasecmp("move ", p, 5)) {
1833 action = SCST_PROC_ACTION_MOVE;
1835 PRINT_ERROR("Unknown action \"%s\"", p);
1841 case SCST_PROC_ACTION_ADD:
1842 case SCST_PROC_ACTION_DEL:
1843 case SCST_PROC_ACTION_MOVE:
1844 while (isspace(*p) && *p != '\0')
1847 while (!isspace(*pp) && *pp != '\0')
1852 while (isspace(*pp) && *pp != '\0')
1856 case SCST_PROC_ACTION_ADD:
1857 case SCST_PROC_ACTION_DEL:
1858 PRINT_ERROR("%s", "Too many "
1868 rc = scst_suspend_activity(true);
1872 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1874 goto out_free_resume;
1878 case SCST_PROC_ACTION_ADD:
1879 rc = scst_acg_add_name(acg, p);
1881 case SCST_PROC_ACTION_DEL:
1882 rc = scst_acg_remove_name(acg, p, true);
1884 case SCST_PROC_ACTION_MOVE:
1886 struct scst_acg *a, *new_acg = NULL;
1889 while (!isspace(*pp) && *pp != '\0')
1894 while (isspace(*pp) && *pp != '\0')
1897 PRINT_ERROR("%s", "Too many arguments");
1899 goto out_free_unlock;
1902 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1903 if (strcmp(a->acg_name, p) == 0) {
1904 TRACE_DBG("group (acg) %p %s found",
1910 if (new_acg == NULL) {
1911 PRINT_ERROR("Group %s not found", p);
1913 goto out_free_unlock;
1915 rc = scst_acg_remove_name(acg, name, false);
1917 goto out_free_unlock;
1918 rc = scst_acg_add_name(new_acg, name);
1921 case SCST_PROC_ACTION_CLEAR:
1922 list_for_each_entry_safe(n, nn, &acg->acn_list,
1924 __scst_acg_remove_acn(n);
1926 scst_check_reassign_sessions();
1931 mutex_unlock(&scst_mutex);
1934 scst_resume_activity();
1937 free_page((unsigned long)buffer);
1943 TRACE_EXIT_RES(res);
1947 static int scst_version_info_show(struct seq_file *seq, void *v)
1951 seq_printf(seq, "%s\n", SCST_VERSION_STRING);
1953 #ifdef CONFIG_SCST_STRICT_SERIALIZING
1954 seq_printf(seq, "Strict serializing enabled\n");
1957 #ifdef CONFIG_SCST_EXTRACHECKS
1958 seq_printf(seq, "EXTRACHECKS\n");
1961 #ifdef CONFIG_SCST_TRACING
1962 seq_printf(seq, "TRACING\n");
1965 #ifdef CONFIG_SCST_DEBUG
1966 seq_printf(seq, "DEBUG\n");
1969 #ifdef CONFIG_SCST_DEBUG_TM
1970 seq_printf(seq, "DEBUG_TM\n");
1973 #ifdef CONFIG_SCST_DEBUG_RETRY
1974 seq_printf(seq, "DEBUG_RETRY\n");
1977 #ifdef CONFIG_SCST_DEBUG_OOM
1978 seq_printf(seq, "DEBUG_OOM\n");
1981 #ifdef CONFIG_SCST_DEBUG_SN
1982 seq_printf(seq, "DEBUG_SN\n");
1985 #ifdef CONFIG_SCST_USE_EXPECTED_VALUES
1986 seq_printf(seq, "USE_EXPECTED_VALUES\n");
1989 #ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
1990 seq_printf(seq, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
1993 #ifdef CONFIG_SCST_STRICT_SECURITY
1994 seq_printf(seq, "SCST_STRICT_SECURITY\n");
2001 static struct scst_proc_data scst_version_proc_data = {
2002 SCST_DEF_RW_SEQ_OP(NULL)
2003 .show = scst_version_info_show,
2006 static int scst_help_info_show(struct seq_file *seq, void *v)
2010 seq_printf(seq, "%s\n", scst_proc_help_string);
2016 static struct scst_proc_data scst_help_proc_data = {
2017 SCST_DEF_RW_SEQ_OP(NULL)
2018 .show = scst_help_info_show,
2021 static int scst_dev_handler_type_info_show(struct seq_file *seq, void *v)
2023 struct scst_dev_type *dev_type = (struct scst_dev_type *)seq->private;
2027 seq_printf(seq, "%d - %s\n", dev_type->type,
2028 dev_type->type > (int)ARRAY_SIZE(scst_proc_dev_handler_type)
2029 ? "unknown" : scst_proc_dev_handler_type[dev_type->type]);
2035 static struct scst_proc_data scst_dev_handler_type_proc_data = {
2036 SCST_DEF_RW_SEQ_OP(NULL)
2037 .show = scst_dev_handler_type_info_show,
2040 static int scst_sessions_info_show(struct seq_file *seq, void *v)
2043 struct scst_acg *acg;
2044 struct scst_session *sess;
2048 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2053 seq_printf(seq, "%-20s %-45s %-35s %-15s\n",
2054 "Target name", "Initiator name",
2055 "Group name", "Command Count");
2057 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
2058 list_for_each_entry(sess, &acg->acg_sess_list,
2059 acg_sess_list_entry) {
2060 seq_printf(seq, "%-20s %-45s %-35s %-15d\n",
2061 sess->tgt->tgtt->name,
2062 sess->initiator_name,
2064 atomic_read(&sess->sess_cmd_count));
2068 mutex_unlock(&scst_mutex);
2071 TRACE_EXIT_RES(res);
2075 static struct scst_proc_data scst_sessions_proc_data = {
2076 SCST_DEF_RW_SEQ_OP(NULL)
2077 .show = scst_sessions_info_show,
2081 static struct scst_proc_data scst_sgv_proc_data = {
2082 SCST_DEF_RW_SEQ_OP(NULL)
2083 .show = sgv_procinfo_show,
2086 static int scst_groups_names_show(struct seq_file *seq, void *v)
2089 struct scst_acg *acg = (struct scst_acg *)seq->private;
2090 struct scst_acn *name;
2094 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2099 list_for_each_entry(name, &acg->acn_list, acn_list_entry) {
2100 seq_printf(seq, "%s\n", name->name);
2103 mutex_unlock(&scst_mutex);
2106 TRACE_EXIT_RES(res);
2110 static struct scst_proc_data scst_groups_names_proc_data = {
2111 SCST_DEF_RW_SEQ_OP(scst_proc_groups_names_write)
2112 .show = scst_groups_names_show,
2115 static int scst_groups_devices_show(struct seq_file *seq, void *v)
2118 struct scst_acg *acg = (struct scst_acg *)seq->private;
2119 struct scst_acg_dev *acg_dev;
2123 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2128 seq_printf(seq, "%-60s%-13s%s\n", "Device (host:ch:id:lun or name)",
2131 list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
2132 if (acg_dev->dev->virt_id == 0) {
2134 int size = sizeof(conv);
2136 memset(conv, 0, size);
2137 size = snprintf(conv, size, "%d:%d:%d:",
2138 acg_dev->dev->scsi_dev->host->host_no,
2139 acg_dev->dev->scsi_dev->channel,
2140 acg_dev->dev->scsi_dev->id);
2141 seq_printf(seq, "%s", conv);
2144 * For some reason the third string argument always
2145 * shown as NULL, so we have to split it on 2 calls.
2147 sprintf(conv, "%%-%dd%%-13d", 60 - size);
2148 size += seq_printf(seq, conv,
2149 acg_dev->dev->scsi_dev->lun,
2151 seq_printf(seq, "%s\n",
2152 acg_dev->rd_only ? "RO" : "");
2154 seq_printf(seq, "%-60s%-13lld%s\n",
2155 acg_dev->dev->virt_name,
2156 (long long unsigned int)acg_dev->lun,
2157 acg_dev->rd_only ? "RO" : "");
2160 mutex_unlock(&scst_mutex);
2163 TRACE_EXIT_RES(res);
2167 static struct scst_proc_data scst_groups_devices_proc_data = {
2168 SCST_DEF_RW_SEQ_OP(scst_proc_groups_devices_write)
2169 .show = scst_groups_devices_show,
2172 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2174 static int scst_proc_read_tlb(const struct scst_proc_log *tbl,
2175 struct seq_file *seq,
2176 unsigned long log_level, int *first)
2178 const struct scst_proc_log *t = tbl;
2182 if (log_level & t->val) {
2183 seq_printf(seq, "%s%s", *first ? "" : " | ", t->token);
2191 int scst_proc_log_entry_read(struct seq_file *seq, unsigned long log_level,
2192 const struct scst_proc_log *tbl)
2194 int res = 0, first = 1;
2198 scst_proc_read_tlb(scst_proc_trace_tbl, seq, log_level, &first);
2201 scst_proc_read_tlb(tbl, seq, log_level, &first);
2203 seq_printf(seq, "%s\n", first ? "none" : "");
2205 TRACE_EXIT_RES(res);
2208 EXPORT_SYMBOL(scst_proc_log_entry_read);
2210 static int log_info_show(struct seq_file *seq, void *v)
2216 if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
2221 res = scst_proc_log_entry_read(seq, trace_flag,
2222 scst_proc_local_trace_tbl);
2224 mutex_unlock(&scst_log_mutex);
2227 TRACE_EXIT_RES(res);
2231 static struct scst_proc_data scst_log_proc_data = {
2232 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_log)
2233 .show = log_info_show,
2239 static int scst_tgt_info_show(struct seq_file *seq, void *v)
2242 struct scst_device *dev;
2246 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2251 seq_printf(seq, "%-60s%s\n", "Device (host:ch:id:lun or name)",
2253 list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
2254 if (dev->virt_id == 0) {
2256 int size = sizeof(conv);
2257 size = snprintf(conv, size, "%d:%d:%d:",
2258 dev->scsi_dev->host->host_no,
2259 dev->scsi_dev->channel,
2261 seq_printf(seq, "%s", conv);
2262 sprintf(conv, "%%-%dd%%s\n", 60 - size);
2263 seq_printf(seq, conv, dev->scsi_dev->lun,
2264 dev->handler ? dev->handler->name : "-");
2266 seq_printf(seq, "%-60s%s\n",
2267 dev->virt_name, dev->handler->name);
2270 mutex_unlock(&scst_mutex);
2273 TRACE_EXIT_RES(res);
2277 static struct scst_proc_data scst_tgt_proc_data = {
2278 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write)
2279 .show = scst_tgt_info_show,
2282 static int scst_threads_info_show(struct seq_file *seq, void *v)
2286 seq_printf(seq, "%d\n", scst_global_threads_count());
2292 static struct scst_proc_data scst_threads_proc_data = {
2293 SCST_DEF_RW_SEQ_OP(scst_proc_threads_write)
2294 .show = scst_threads_info_show,
2297 static int scst_scsi_tgtinfo_show(struct seq_file *seq, void *v)
2299 struct scst_tgt *vtt = seq->private;
2304 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2309 if (vtt->tgtt->read_proc)
2310 res = vtt->tgtt->read_proc(seq, vtt);
2312 mutex_unlock(&scst_proc_mutex);
2314 TRACE_EXIT_RES(res);
2318 static struct scst_proc_data scst_scsi_tgt_proc_data = {
2319 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_write)
2320 .show = scst_scsi_tgtinfo_show,
2323 static int scst_dev_handler_info_show(struct seq_file *seq, void *v)
2325 struct scst_dev_type *dev_type = seq->private;
2330 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2335 if (dev_type->read_proc)
2336 res = dev_type->read_proc(seq, dev_type);
2338 mutex_unlock(&scst_proc_mutex);
2341 TRACE_EXIT_RES(res);
2345 static struct scst_proc_data scst_dev_handler_proc_data = {
2346 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_dev_handler_write)
2347 .show = scst_dev_handler_info_show,
2350 struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry *root,
2351 const char *name, struct scst_proc_data *pdata)
2353 struct proc_dir_entry *p = NULL;
2360 mode = S_IFREG | S_IRUGO | (pdata->seq_op.write ? S_IWUSR : 0);
2361 p = create_proc_entry(name, mode, root);
2363 PRINT_ERROR("Fail to create entry %s in /proc", name);
2365 p->proc_fops = &pdata->seq_op;
2366 p->data = pdata->data;
2373 EXPORT_SYMBOL(scst_create_proc_entry);
2375 int scst_single_seq_open(struct inode *inode, struct file *file)
2377 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
2378 struct scst_proc_data *pdata = container_of(PDE(inode)->proc_fops,
2379 struct scst_proc_data, seq_op);
2381 struct scst_proc_data *pdata = container_of(inode->i_fop,
2382 struct scst_proc_data, seq_op);
2384 return single_open(file, pdata->show, PDE(inode)->data);
2386 EXPORT_SYMBOL(scst_single_seq_open);