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 (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3)
189 #if !defined(CONFIG_PPC)
191 * If strcasecmp() and strncasecmp() have already been declared in
192 * <linux/string.h>, do not redefine these functions. Declarations for these
193 * functions are present in the <linux/string.h> header of the following
195 * - The PPC kernel headers for all kernel versions supported by SCST.
196 * - Kernel version 2.6.22 and later for all architectures.
197 * - RHEL 5.3 and later.
199 * Notes about the above preprocessor statement:
200 * - We can't use RHEL_RELEASE_CODE(5, 3) because it would trigger an error on
201 * non-RHEL/CentOS systems -- this expression would expand to "(5,3)".
202 * - There is no space between the minus sign and the zero in the expression
203 * "RHEL_RELEASE_CODE -0" such that it expands to a syntactically valid
204 * expression on non-RHEL/CentOS systems ("-0").
205 * - The above statement has been put on one long line because as of r800
206 * scripts/specialize-patch does not yet handle multi-line preprocessor
207 * statements correctly.
210 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
211 static int strcasecmp(const char *s1, const char *s2)
217 } while (c1 == c2 && c1 != 0);
222 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
223 static int strncasecmp(const char *s1, const char *s2, int n)
225 static int strncasecmp(const char *s1, const char *s2, size_t n)
232 } while ((--n > 0) && c1 == c2 && c1 != 0);
236 #endif /* !CONFIG_PPC */
237 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3) */
239 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
241 static DEFINE_MUTEX(scst_log_mutex);
243 int scst_proc_log_entry_write(struct file *file, const char __user *buf,
244 unsigned long length, unsigned long *log_level,
245 unsigned long default_level, const struct scst_proc_log *tbl)
249 unsigned long level = 0, oldlevel;
250 char *buffer, *p, *e;
251 const struct scst_proc_log *t;
252 char *data = (char *)PDE(file->f_dentry->d_inode)->data;
256 if (length > SCST_PROC_BLOCK_SIZE) {
264 buffer = (char *)__get_free_page(GFP_KERNEL);
269 if (copy_from_user(buffer, buf, length)) {
273 if (length < PAGE_SIZE) {
274 buffer[length] = '\0';
275 } else if (buffer[PAGE_SIZE-1]) {
282 * echo "all|none|default" >/proc/scsi_tgt/trace_level
283 * echo "value DEC|0xHEX|0OCT" >/proc/scsi_tgt/trace_level
284 * echo "set|add|clear|del TOKEN" >/proc/scsi_tgt/trace_level
285 * where TOKEN is one of [debug,function,line,pid,entryexit,
286 * buff,mem,sg,out_of_mem,retry,
287 * scsi_serializing,special,scsi,mgmt,minor,...]
290 if (!strncasecmp("all", p, 3)) {
291 action = SCST_PROC_ACTION_ALL;
292 } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) {
293 action = SCST_PROC_ACTION_NONE;
294 } else if (!strncasecmp("default", p, 7)) {
295 action = SCST_PROC_ACTION_DEFAULT;
296 } else if (!strncasecmp("set ", p, 4)) {
298 action = SCST_PROC_ACTION_SET;
299 } else if (!strncasecmp("add ", p, 4)) {
301 action = SCST_PROC_ACTION_ADD;
302 } else if (!strncasecmp("del ", p, 4)) {
304 action = SCST_PROC_ACTION_DEL;
305 } else if (!strncasecmp("value ", p, 6)) {
307 action = SCST_PROC_ACTION_VALUE;
309 if (p[strlen(p) - 1] == '\n')
310 p[strlen(p) - 1] = '\0';
311 PRINT_ERROR("Unknown action \"%s\"", p);
317 case SCST_PROC_ACTION_ALL:
320 case SCST_PROC_ACTION_DEFAULT:
321 level = default_level;
323 case SCST_PROC_ACTION_NONE:
326 case SCST_PROC_ACTION_SET:
327 case SCST_PROC_ACTION_ADD:
328 case SCST_PROC_ACTION_DEL:
329 while (isspace(*p) && *p != '\0')
332 while (!isspace(*e) && *e != '\0')
338 if (!strcasecmp(p, t->token)) {
346 t = scst_proc_trace_tbl;
348 if (!strcasecmp(p, t->token)) {
356 PRINT_ERROR("Unknown token \"%s\"", p);
361 case SCST_PROC_ACTION_VALUE:
362 while (isspace(*p) && *p != '\0')
364 level = simple_strtoul(p, NULL, 0);
368 oldlevel = *log_level;
371 case SCST_PROC_ACTION_ADD:
374 case SCST_PROC_ACTION_DEL:
375 *log_level &= ~level;
382 PRINT_INFO("Changed trace level for \"%s\": "
383 "old 0x%08lx, new 0x%08lx",
384 (char *)data, oldlevel, *log_level);
387 free_page((unsigned long)buffer);
392 EXPORT_SYMBOL(scst_proc_log_entry_write);
394 static ssize_t scst_proc_scsi_tgt_gen_write_log(struct file *file,
395 const char __user *buf,
396 size_t length, loff_t *off)
402 if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
407 res = scst_proc_log_entry_write(file, buf, length,
408 &trace_flag, SCST_DEFAULT_LOG_FLAGS,
409 scst_proc_local_trace_tbl);
411 mutex_unlock(&scst_log_mutex);
418 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
420 #ifdef CONFIG_SCST_MEASURE_LATENCY
422 static int lat_info_show(struct seq_file *seq, void *v)
425 struct scst_acg *acg;
426 struct scst_session *sess;
430 if (mutex_lock_interruptible(&scst_mutex) != 0) {
435 seq_printf(seq, "%-20s %-45s %-15s %15s\n",
439 "Processing latency (ns)");
441 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
442 list_for_each_entry(sess, &acg->acg_sess_list,
443 acg_sess_list_entry) {
444 unsigned long proc_lat = 0, scst_lat = 0;
445 uint64_t proc_time, scst_time;
446 unsigned int processed_cmds;
448 spin_lock_bh(&sess->meas_lock);
449 proc_time = sess->processing_time;
450 scst_time = sess->scst_time;
451 processed_cmds = sess->processed_cmds;
452 spin_unlock_bh(&sess->meas_lock);
454 TRACE_DBG("sess %p, scst_time %lld, proc_time %lld, "
455 "processed_cmds %d", sess, scst_time,
456 proc_time, processed_cmds);
458 #if BITS_PER_LONG == 32
459 /* Unfortunately, do_div() doesn't work too well */
460 while (((proc_time & 0xFFFFFFFF00000000LL) != 0) ||
461 ((scst_time & 0xFFFFFFFF00000000LL) != 0)) {
462 TRACE_DBG("%s", "Gathered time too big");
465 processed_cmds >>= 1;
469 if (sess->processed_cmds != 0) {
470 proc_lat = (unsigned long)proc_time /
472 scst_lat = (unsigned long)scst_time /
476 seq_printf(seq, "%-20s %-45s %-15ld %-15ld\n",
477 sess->tgt->tgtt->name,
478 sess->initiator_name,
483 mutex_unlock(&scst_mutex);
490 static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file,
491 const char __user *buf,
492 size_t length, loff_t *off)
495 struct scst_acg *acg;
496 struct scst_session *sess;
500 if (mutex_lock_interruptible(&scst_mutex) != 0) {
505 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
506 list_for_each_entry(sess, &acg->acg_sess_list,
507 acg_sess_list_entry) {
508 PRINT_INFO("Zeroing latency statistics for initiator"
510 sess->initiator_name);
511 spin_lock_bh(&sess->meas_lock);
512 sess->processing_time = 0;
514 sess->processed_cmds = 0;
515 spin_unlock_bh(&sess->meas_lock);
519 mutex_unlock(&scst_mutex);
526 static struct scst_proc_data scst_lat_proc_data = {
527 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_lat)
528 .show = lat_info_show,
532 #endif /* CONFIG_SCST_MEASURE_LATENCY */
534 static int __init scst_proc_init_module_log(void)
537 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) || \
538 defined(CONFIG_SCST_MEASURE_LATENCY)
539 struct proc_dir_entry *generic;
544 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
545 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
546 SCST_PROC_LOG_ENTRY_NAME,
547 &scst_log_proc_data);
549 PRINT_ERROR("cannot init /proc/%s/%s",
550 SCST_PROC_ENTRY_NAME, SCST_PROC_LOG_ENTRY_NAME);
555 #ifdef CONFIG_SCST_MEASURE_LATENCY
557 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
558 SCST_PROC_LAT_ENTRY_NAME,
559 &scst_lat_proc_data);
561 PRINT_ERROR("cannot init /proc/%s/%s",
562 SCST_PROC_ENTRY_NAME,
563 SCST_PROC_LAT_ENTRY_NAME);
573 static void scst_proc_cleanup_module_log(void)
577 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
578 remove_proc_entry(SCST_PROC_LOG_ENTRY_NAME, scst_proc_scsi_tgt);
581 #ifdef CONFIG_SCST_MEASURE_LATENCY
582 remove_proc_entry(SCST_PROC_LAT_ENTRY_NAME, scst_proc_scsi_tgt);
589 static int scst_proc_group_add_tree(struct scst_acg *acg, const char *name)
592 struct proc_dir_entry *generic;
596 acg->acg_proc_root = proc_mkdir(name, scst_proc_groups_root);
597 if (acg->acg_proc_root == NULL) {
598 PRINT_ERROR("Not enough memory to register %s entry in "
599 "/proc/%s/%s", name, SCST_PROC_ENTRY_NAME,
600 SCST_PROC_GROUPS_ENTRY_NAME);
604 scst_groups_devices_proc_data.data = acg;
605 generic = scst_create_proc_entry(acg->acg_proc_root,
606 SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
607 &scst_groups_devices_proc_data);
609 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
610 SCST_PROC_ENTRY_NAME,
611 SCST_PROC_GROUPS_ENTRY_NAME,
612 name, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME);
617 scst_groups_names_proc_data.data = acg;
618 generic = scst_create_proc_entry(acg->acg_proc_root,
619 SCST_PROC_GROUPS_USERS_ENTRY_NAME,
620 &scst_groups_names_proc_data);
622 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
623 SCST_PROC_ENTRY_NAME,
624 SCST_PROC_GROUPS_ENTRY_NAME,
625 name, SCST_PROC_GROUPS_USERS_ENTRY_NAME);
635 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
639 remove_proc_entry(name, scst_proc_groups_root);
643 static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
648 remove_proc_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME, acg_proc_root);
649 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
651 remove_proc_entry(name, scst_proc_groups_root);
657 /* The activity supposed to be suspended and scst_mutex held */
658 static int scst_proc_group_add(const char *p)
660 int res = 0, len = strlen(p) + 1;
661 struct scst_acg *acg;
666 name = kmalloc(len, GFP_KERNEL);
668 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of name failed");
671 strncpy(name, p, len);
673 acg = scst_alloc_add_acg(name);
675 PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", name);
679 res = scst_proc_group_add_tree(acg, p);
688 scst_proc_del_free_acg(acg, 0);
698 /* The activity supposed to be suspended and scst_mutex held */
699 static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc)
702 struct proc_dir_entry *acg_proc_root = acg->acg_proc_root;
707 if (acg != scst_default_acg) {
708 name = acg->acg_name;
709 res = scst_destroy_acg(acg);
712 scst_proc_del_acg_tree(acg_proc_root, name);
721 /* The activity supposed to be suspended and scst_mutex held */
722 static int scst_proc_rename_acg(struct scst_acg *acg, const char *new_name)
724 int res = 0, len = strlen(new_name) + 1;
726 struct proc_dir_entry *old_acg_proc_root = acg->acg_proc_root;
730 name = kmalloc(len, GFP_KERNEL);
732 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of new name failed");
735 strncpy(name, new_name, len);
737 res = scst_proc_group_add_tree(acg, new_name);
741 scst_proc_del_acg_tree(old_acg_proc_root, acg->acg_name);
743 kfree(acg->acg_name);
744 acg->acg_name = name;
746 scst_check_reassign_sessions();
760 static int __init scst_proc_init_groups(void)
766 /* create the proc directory entry for the device */
767 scst_proc_groups_root = proc_mkdir(SCST_PROC_GROUPS_ENTRY_NAME,
769 if (scst_proc_groups_root == NULL) {
770 PRINT_ERROR("Not enough memory to register %s entry in "
771 "/proc/%s", SCST_PROC_GROUPS_ENTRY_NAME,
772 SCST_PROC_ENTRY_NAME);
776 res = scst_proc_group_add_tree(scst_default_acg,
777 SCST_DEFAULT_ACG_NAME);
786 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
793 static void scst_proc_cleanup_groups(void)
795 struct scst_acg *acg_tmp, *acg;
799 /* remove all groups (dir & entries) */
800 list_for_each_entry_safe(acg, acg_tmp, &scst_acg_list,
801 scst_acg_list_entry) {
802 scst_proc_del_free_acg(acg, 1);
805 scst_proc_del_acg_tree(scst_default_acg->acg_proc_root,
806 SCST_DEFAULT_ACG_NAME);
807 TRACE_DBG("remove_proc_entry(%s, %p)",
808 SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
809 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
814 static int __init scst_proc_init_sgv(void)
817 struct proc_dir_entry *pr;
821 pr = scst_create_proc_entry(scst_proc_scsi_tgt, "sgv",
822 &scst_sgv_proc_data);
824 PRINT_ERROR("%s", "cannot create sgv /proc entry");
832 static void __exit scst_proc_cleanup_sgv(void)
835 remove_proc_entry("sgv", scst_proc_scsi_tgt);
839 int __init scst_proc_init_module(void)
842 struct proc_dir_entry *generic;
846 scst_proc_scsi_tgt = proc_mkdir(SCST_PROC_ENTRY_NAME, NULL);
847 if (!scst_proc_scsi_tgt) {
848 PRINT_ERROR("cannot init /proc/%s", SCST_PROC_ENTRY_NAME);
852 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
853 SCST_PROC_ENTRY_NAME,
854 &scst_tgt_proc_data);
856 PRINT_ERROR("cannot init /proc/%s/%s",
857 SCST_PROC_ENTRY_NAME, SCST_PROC_ENTRY_NAME);
861 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
862 SCST_PROC_VERSION_NAME,
863 &scst_version_proc_data);
865 PRINT_ERROR("cannot init /proc/%s/%s",
866 SCST_PROC_ENTRY_NAME, SCST_PROC_VERSION_NAME);
870 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
871 SCST_PROC_SESSIONS_NAME,
872 &scst_sessions_proc_data);
874 PRINT_ERROR("cannot init /proc/%s/%s",
875 SCST_PROC_ENTRY_NAME, SCST_PROC_SESSIONS_NAME);
879 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
881 &scst_help_proc_data);
883 PRINT_ERROR("cannot init /proc/%s/%s",
884 SCST_PROC_ENTRY_NAME, SCST_PROC_HELP_NAME);
888 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
889 SCST_PROC_THREADS_NAME,
890 &scst_threads_proc_data);
892 PRINT_ERROR("cannot init /proc/%s/%s",
893 SCST_PROC_ENTRY_NAME, SCST_PROC_THREADS_NAME);
897 if (scst_proc_init_module_log() < 0)
900 if (scst_proc_init_groups() < 0)
903 if (scst_proc_init_sgv() < 0)
911 scst_proc_cleanup_groups();
914 scst_proc_cleanup_module_log();
917 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
920 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
923 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
926 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
929 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
932 remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
939 void __exit scst_proc_cleanup_module(void)
943 /* We may not bother about locks here */
944 scst_proc_cleanup_sgv();
945 scst_proc_cleanup_groups();
946 scst_proc_cleanup_module_log();
947 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
948 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
949 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
950 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
951 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
952 remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
957 static ssize_t scst_proc_threads_write(struct file *file,
958 const char __user *buf,
959 size_t length, loff_t *off)
962 int oldtn, newtn, delta;
967 if (length > SCST_PROC_BLOCK_SIZE) {
975 buffer = (char *)__get_free_page(GFP_KERNEL);
980 if (copy_from_user(buffer, buf, length)) {
984 if (length < PAGE_SIZE) {
985 buffer[length] = '\0';
986 } else if (buffer[PAGE_SIZE-1]) {
991 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
996 mutex_lock(&scst_global_threads_mutex);
998 oldtn = scst_nr_global_threads;
999 newtn = simple_strtoul(buffer, NULL, 0);
1001 PRINT_ERROR("Illegal threads num value %d", newtn);
1003 goto out_up_thr_free;
1005 delta = newtn - oldtn;
1007 __scst_del_global_threads(-delta);
1009 __scst_add_global_threads(delta);
1011 PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
1014 mutex_unlock(&scst_global_threads_mutex);
1016 mutex_unlock(&scst_proc_mutex);
1019 free_page((unsigned long)buffer);
1021 TRACE_EXIT_RES(res);
1025 int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt)
1031 /* create the proc directory entry for the device */
1032 vtt->proc_tgt_root = proc_mkdir(vtt->name, scst_proc_scsi_tgt);
1033 if (vtt->proc_tgt_root == NULL) {
1034 PRINT_ERROR("Not enough memory to register SCSI target %s "
1035 "in /proc/%s", vtt->name, SCST_PROC_ENTRY_NAME);
1040 TRACE_EXIT_RES(res);
1048 void scst_cleanup_proc_target_dir_entries(struct scst_tgt_template *vtt)
1052 remove_proc_entry(vtt->name, scst_proc_scsi_tgt);
1058 /* Called under scst_mutex */
1059 int scst_build_proc_target_entries(struct scst_tgt *vtt)
1062 struct proc_dir_entry *p;
1067 if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1068 /* create the proc file entry for the device */
1069 scnprintf(name, sizeof(name), "%d", vtt->tgtt->proc_dev_num);
1070 scst_scsi_tgt_proc_data.data = (void *)vtt;
1071 p = scst_create_proc_entry(vtt->tgtt->proc_tgt_root,
1073 &scst_scsi_tgt_proc_data);
1075 PRINT_ERROR("Not enough memory to register SCSI "
1076 "target entry %s in /proc/%s/%s", name,
1077 SCST_PROC_ENTRY_NAME, vtt->tgtt->name);
1081 vtt->proc_num = vtt->tgtt->proc_dev_num;
1082 vtt->tgtt->proc_dev_num++;
1086 TRACE_EXIT_RES(res);
1090 void scst_cleanup_proc_target_entries(struct scst_tgt *vtt)
1096 if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1097 scnprintf(name, sizeof(name), "%d", vtt->proc_num);
1098 remove_proc_entry(name, vtt->tgtt->proc_tgt_root);
1105 static ssize_t scst_proc_scsi_tgt_write(struct file *file,
1106 const char __user *buf,
1107 size_t length, loff_t *off)
1109 struct scst_tgt *vtt =
1110 (struct scst_tgt *)PDE(file->f_dentry->d_inode)->data;
1118 if (vtt->tgtt->write_proc == NULL) {
1123 if (length > SCST_PROC_BLOCK_SIZE) {
1131 buffer = (char *)__get_free_page(GFP_KERNEL);
1136 if (copy_from_user(buffer, buf, length)) {
1140 if (length < PAGE_SIZE) {
1141 buffer[length] = '\0';
1142 } else if (buffer[PAGE_SIZE-1]) {
1147 TRACE_BUFFER("Buffer", buffer, length);
1149 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1154 res = vtt->tgtt->write_proc(buffer, &start, 0, length, &eof, vtt);
1156 mutex_unlock(&scst_proc_mutex);
1159 free_page((unsigned long)buffer);
1161 TRACE_EXIT_RES(res);
1165 int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1168 struct proc_dir_entry *p;
1172 sBUG_ON(dev_type->proc_dev_type_root);
1174 /* create the proc directory entry for the dev type handler */
1175 dev_type->proc_dev_type_root = proc_mkdir(dev_type->name,
1176 scst_proc_scsi_tgt);
1177 if (dev_type->proc_dev_type_root == NULL) {
1178 PRINT_ERROR("Not enough memory to register dev handler dir "
1179 "%s in /proc/%s", dev_type->name, SCST_PROC_ENTRY_NAME);
1183 scst_dev_handler_type_proc_data.data = dev_type;
1184 if (dev_type->type >= 0) {
1185 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1186 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1187 &scst_dev_handler_type_proc_data);
1189 PRINT_ERROR("Not enough memory to register dev "
1190 "handler entry %s in /proc/%s/%s",
1191 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1192 SCST_PROC_ENTRY_NAME, dev_type->name);
1197 if (dev_type->read_proc || dev_type->write_proc) {
1198 /* create the proc file entry for the dev type handler */
1199 scst_dev_handler_proc_data.data = (void *)dev_type;
1200 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1202 &scst_dev_handler_proc_data);
1204 PRINT_ERROR("Not enough memory to register dev "
1205 "handler entry %s in /proc/%s/%s", dev_type->name,
1206 SCST_PROC_ENTRY_NAME, dev_type->name);
1212 TRACE_EXIT_RES(res);
1216 if (dev_type->type >= 0)
1217 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1218 dev_type->proc_dev_type_root);
1221 remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1228 void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1232 sBUG_ON(dev_type->proc_dev_type_root == NULL);
1234 if (dev_type->type >= 0) {
1235 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1236 dev_type->proc_dev_type_root);
1238 if (dev_type->read_proc || dev_type->write_proc)
1239 remove_proc_entry(dev_type->name, dev_type->proc_dev_type_root);
1240 remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1241 dev_type->proc_dev_type_root = NULL;
1247 static ssize_t scst_proc_scsi_dev_handler_write(struct file *file,
1248 const char __user *buf,
1249 size_t length, loff_t *off)
1251 struct scst_dev_type *dev_type =
1252 (struct scst_dev_type *)PDE(file->f_dentry->d_inode)->data;
1260 if (dev_type->write_proc == NULL) {
1265 if (length > SCST_PROC_BLOCK_SIZE) {
1274 buffer = (char *)__get_free_page(GFP_KERNEL);
1280 if (copy_from_user(buffer, buf, length)) {
1284 if (length < PAGE_SIZE) {
1285 buffer[length] = '\0';
1286 } else if (buffer[PAGE_SIZE-1]) {
1291 TRACE_BUFFER("Buffer", buffer, length);
1293 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1298 res = dev_type->write_proc(buffer, &start, 0, length, &eof, dev_type);
1300 mutex_unlock(&scst_proc_mutex);
1303 free_page((unsigned long)buffer);
1306 TRACE_EXIT_RES(res);
1310 static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file,
1311 const char __user *buf,
1312 size_t length, loff_t *off)
1314 int res, rc = 0, action;
1315 char *buffer, *p, *pp;
1316 struct scst_acg *a, *acg = NULL;
1320 if (length > SCST_PROC_BLOCK_SIZE) {
1328 buffer = (char *)__get_free_page(GFP_KERNEL);
1333 if (copy_from_user(buffer, buf, length)) {
1337 if (length < PAGE_SIZE) {
1338 buffer[length] = '\0';
1339 } else if (buffer[PAGE_SIZE-1]) {
1345 * Usage: echo "add_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1346 * or echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1347 * or echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt"
1348 * or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt
1351 if (p[strlen(p) - 1] == '\n')
1352 p[strlen(p) - 1] = '\0';
1353 if (!strncasecmp("assign ", p, 7)) {
1355 action = SCST_PROC_ACTION_ASSIGN;
1356 } else if (!strncasecmp("add_group ", p, 10)) {
1358 action = SCST_PROC_ACTION_ADD_GROUP;
1359 } else if (!strncasecmp("del_group ", p, 10)) {
1361 action = SCST_PROC_ACTION_DEL_GROUP;
1362 } else if (!strncasecmp("rename_group ", p, 13)) {
1364 action = SCST_PROC_ACTION_RENAME_GROUP;
1366 PRINT_ERROR("Unknown action \"%s\"", p);
1371 res = scst_suspend_activity(true);
1375 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1377 goto out_free_resume;
1383 case SCST_PROC_ACTION_ADD_GROUP:
1384 case SCST_PROC_ACTION_DEL_GROUP:
1385 case SCST_PROC_ACTION_RENAME_GROUP:
1387 while (!isspace(*pp) && *pp != '\0')
1392 while (isspace(*pp) && *pp != '\0')
1396 case SCST_PROC_ACTION_ADD_GROUP:
1397 case SCST_PROC_ACTION_DEL_GROUP:
1398 PRINT_ERROR("%s", "Too many "
1406 if (strcmp(p, SCST_DEFAULT_ACG_NAME) == 0) {
1407 PRINT_ERROR("Attempt to add/delete/rename predefined "
1413 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1414 if (strcmp(a->acg_name, p) == 0) {
1415 TRACE_DBG("group (acg) %p %s found",
1423 case SCST_PROC_ACTION_ADD_GROUP:
1425 PRINT_ERROR("acg name %s exist", p);
1429 rc = scst_proc_group_add(p);
1431 case SCST_PROC_ACTION_DEL_GROUP:
1433 PRINT_ERROR("acg name %s not found", p);
1437 rc = scst_proc_del_free_acg(acg, 1);
1439 case SCST_PROC_ACTION_RENAME_GROUP:
1441 PRINT_ERROR("acg name %s not found", p);
1447 while (!isspace(*pp) && *pp != '\0')
1452 while (isspace(*pp) && *pp != '\0')
1455 PRINT_ERROR("%s", "Too many arguments");
1460 rc = scst_proc_rename_acg(acg, p);
1464 case SCST_PROC_ACTION_ASSIGN:
1465 rc = scst_proc_assign_handler(p);
1473 mutex_unlock(&scst_mutex);
1476 scst_resume_activity();
1479 free_page((unsigned long)buffer);
1482 TRACE_EXIT_RES(res);
1486 /* The activity supposed to be suspended and scst_mutex held */
1487 static int scst_proc_assign_handler(char *buf)
1490 char *p = buf, *e, *ee;
1491 unsigned long host, channel = 0, id = 0, lun = 0;
1492 struct scst_device *d, *dev = NULL;
1493 struct scst_dev_type *dt, *handler = NULL;
1497 while (isspace(*p) && *p != '\0')
1500 host = simple_strtoul(p, &p, 0);
1501 if ((host == ULONG_MAX) || (*p != ':'))
1504 channel = simple_strtoul(p, &p, 0);
1505 if ((channel == ULONG_MAX) || (*p != ':'))
1508 id = simple_strtoul(p, &p, 0);
1509 if ((channel == ULONG_MAX) || (*p != ':'))
1512 lun = simple_strtoul(p, &p, 0);
1513 if (lun == ULONG_MAX)
1518 while (isspace(*e) && *e != '\0')
1521 while (!isspace(*ee) && *ee != '\0')
1525 TRACE_DBG("Dev %ld:%ld:%ld:%ld, handler %s", host, channel, id, lun, e);
1527 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1528 if ((d->virt_id == 0) &&
1529 d->scsi_dev->host->host_no == host &&
1530 d->scsi_dev->channel == channel &&
1531 d->scsi_dev->id == id &&
1532 d->scsi_dev->lun == lun) {
1534 TRACE_DBG("Dev %p (%ld:%ld:%ld:%ld) found",
1535 dev, host, channel, id, lun);
1541 PRINT_ERROR("Device %ld:%ld:%ld:%ld not found",
1542 host, channel, id, lun);
1547 list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
1548 if (!strcmp(dt->name, e)) {
1550 TRACE_DBG("Dev handler %p with name %s found",
1556 if (handler == NULL) {
1557 PRINT_ERROR("Handler %s not found", e);
1562 if (dev->scsi_dev->type != handler->type) {
1563 PRINT_ERROR("Type %d of device %s differs from type "
1564 "%d of dev handler %s", dev->type,
1565 dev->handler->name, handler->type, handler->name);
1570 res = scst_assign_dev_handler(dev, handler);
1573 TRACE_EXIT_RES(res);
1577 PRINT_ERROR("Syntax error on %s", p);
1582 static ssize_t scst_proc_groups_devices_write(struct file *file,
1583 const char __user *buf,
1584 size_t length, loff_t *off)
1586 int res, action, virt = 0, rc, read_only = 0;
1587 char *buffer, *p, *e = NULL;
1588 unsigned int host, channel = 0, id = 0, lun = 0, virt_lun;
1589 struct scst_acg *acg =
1590 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1591 struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
1592 struct scst_device *d, *dev = NULL;
1596 if (length > SCST_PROC_BLOCK_SIZE) {
1604 buffer = (char *)__get_free_page(GFP_KERNEL);
1609 if (copy_from_user(buffer, buf, length)) {
1613 if (length < PAGE_SIZE) {
1614 buffer[length] = '\0';
1615 } else if (buffer[PAGE_SIZE-1]) {
1621 * Usage: echo "add|del H:C:I:L lun [READ_ONLY]" \
1622 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1623 * or echo "replace H:C:I:L lun [READ_ONLY]" \
1624 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1625 * or echo "add|del V_NAME lun [READ_ONLY]" \
1626 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1627 * or echo "replace V_NAME lun [READ_ONLY]" \
1628 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1629 * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/devices
1632 if (p[strlen(p) - 1] == '\n')
1633 p[strlen(p) - 1] = '\0';
1634 if (!strncasecmp("clear", p, 5)) {
1635 action = SCST_PROC_ACTION_CLEAR;
1636 } else if (!strncasecmp("add ", p, 4)) {
1638 action = SCST_PROC_ACTION_ADD;
1639 } else if (!strncasecmp("del ", p, 4)) {
1641 action = SCST_PROC_ACTION_DEL;
1642 } else if (!strncasecmp("replace ", p, 8)) {
1644 action = SCST_PROC_ACTION_REPLACE;
1646 PRINT_ERROR("Unknown action \"%s\"", p);
1651 res = scst_suspend_activity(true);
1655 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1657 goto out_free_resume;
1663 case SCST_PROC_ACTION_ADD:
1664 case SCST_PROC_ACTION_DEL:
1665 case SCST_PROC_ACTION_REPLACE:
1666 while (isspace(*p) && *p != '\0')
1669 host = simple_strtoul(p, &p, 0);
1671 channel = simple_strtoul(p + 1, &p, 0);
1672 id = simple_strtoul(p + 1, &p, 0);
1673 lun = simple_strtoul(p + 1, &p, 0);
1677 p = e; /* restore p */
1678 while (!isspace(*e) && *e != '\0')
1683 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1685 if (d->virt_id && !strcmp(d->virt_name, p)) {
1687 TRACE_DBG("Virt device %p (%s) found",
1693 d->scsi_dev->host->host_no == host &&
1694 d->scsi_dev->channel == channel &&
1695 d->scsi_dev->id == id &&
1696 d->scsi_dev->lun == lun) {
1698 TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
1699 dev, host, channel, id, lun);
1706 PRINT_ERROR("Virt device %s not found", p);
1708 PRINT_ERROR("Device %d:%d:%d:%d not found",
1709 host, channel, id, lun);
1717 /* ToDo: create separate functions */
1720 case SCST_PROC_ACTION_ADD:
1721 case SCST_PROC_ACTION_REPLACE:
1723 bool dev_replaced = false;
1726 while (isspace(*e) && *e != '\0')
1728 virt_lun = simple_strtoul(e, &e, 0);
1730 while (isspace(*e) && *e != '\0')
1734 if (!strncasecmp("READ_ONLY", e, 9))
1737 PRINT_ERROR("Unknown option \"%s\"", e);
1743 list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
1744 acg_dev_list_entry) {
1745 if (acg_dev_tmp->lun == virt_lun) {
1746 acg_dev = acg_dev_tmp;
1750 if (acg_dev != NULL) {
1751 if (action == SCST_PROC_ACTION_ADD) {
1752 PRINT_ERROR("virt lun %d already exists in "
1753 "group %s", virt_lun, acg->acg_name);
1758 rc = scst_acg_remove_dev(acg, acg_dev->dev,
1764 dev_replaced = true;
1768 rc = scst_acg_add_dev(acg, dev, virt_lun, read_only,
1769 action == SCST_PROC_ACTION_ADD);
1776 struct scst_tgt_dev *tgt_dev;
1778 list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
1779 dev_tgt_dev_list_entry) {
1780 if ((tgt_dev->acg_dev->acg == acg) &&
1781 (tgt_dev->lun == virt_lun)) {
1782 TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED"
1783 " on tgt_dev %p", tgt_dev);
1784 scst_gen_aen_or_ua(tgt_dev,
1785 SCST_LOAD_SENSE(scst_sense_inquery_data_changed));
1791 case SCST_PROC_ACTION_DEL:
1792 rc = scst_acg_remove_dev(acg, dev, true);
1798 case SCST_PROC_ACTION_CLEAR:
1799 list_for_each_entry_safe(acg_dev, acg_dev_tmp,
1801 acg_dev_list_entry) {
1802 rc = scst_acg_remove_dev(acg, acg_dev->dev,
1803 list_is_last(&acg_dev->acg_dev_list_entry,
1804 &acg->acg_dev_list));
1814 mutex_unlock(&scst_mutex);
1817 scst_resume_activity();
1820 free_page((unsigned long)buffer);
1823 TRACE_EXIT_RES(res);
1827 static ssize_t scst_proc_groups_names_write(struct file *file,
1828 const char __user *buf,
1829 size_t length, loff_t *off)
1831 int res = length, rc = 0, action;
1832 char *buffer, *p, *pp = NULL;
1833 struct scst_acg *acg =
1834 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1835 struct scst_acn *n, *nn;
1839 if (length > SCST_PROC_BLOCK_SIZE) {
1847 buffer = (char *)__get_free_page(GFP_KERNEL);
1852 if (copy_from_user(buffer, buf, length)) {
1856 if (length < PAGE_SIZE) {
1857 buffer[length] = '\0';
1858 } else if (buffer[PAGE_SIZE-1]) {
1864 * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP_NAME/names
1865 * or echo "move NAME NEW_GROUP_NAME" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names"
1866 * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/names
1869 if (p[strlen(p) - 1] == '\n')
1870 p[strlen(p) - 1] = '\0';
1871 if (!strncasecmp("clear", p, 5)) {
1872 action = SCST_PROC_ACTION_CLEAR;
1873 } else if (!strncasecmp("add ", p, 4)) {
1875 action = SCST_PROC_ACTION_ADD;
1876 } else if (!strncasecmp("del ", p, 4)) {
1878 action = SCST_PROC_ACTION_DEL;
1879 } else if (!strncasecmp("move ", p, 5)) {
1881 action = SCST_PROC_ACTION_MOVE;
1883 PRINT_ERROR("Unknown action \"%s\"", p);
1889 case SCST_PROC_ACTION_ADD:
1890 case SCST_PROC_ACTION_DEL:
1891 case SCST_PROC_ACTION_MOVE:
1892 while (isspace(*p) && *p != '\0')
1895 while (!isspace(*pp) && *pp != '\0')
1900 while (isspace(*pp) && *pp != '\0')
1904 case SCST_PROC_ACTION_ADD:
1905 case SCST_PROC_ACTION_DEL:
1906 PRINT_ERROR("%s", "Too many "
1916 rc = scst_suspend_activity(true);
1920 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1922 goto out_free_resume;
1926 case SCST_PROC_ACTION_ADD:
1927 rc = scst_acg_add_name(acg, p);
1929 case SCST_PROC_ACTION_DEL:
1930 rc = scst_acg_remove_name(acg, p, true);
1932 case SCST_PROC_ACTION_MOVE:
1934 struct scst_acg *a, *new_acg = NULL;
1937 while (!isspace(*pp) && *pp != '\0')
1942 while (isspace(*pp) && *pp != '\0')
1945 PRINT_ERROR("%s", "Too many arguments");
1947 goto out_free_unlock;
1950 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1951 if (strcmp(a->acg_name, p) == 0) {
1952 TRACE_DBG("group (acg) %p %s found",
1958 if (new_acg == NULL) {
1959 PRINT_ERROR("Group %s not found", p);
1961 goto out_free_unlock;
1963 rc = scst_acg_remove_name(acg, name, false);
1965 goto out_free_unlock;
1966 rc = scst_acg_add_name(new_acg, name);
1969 case SCST_PROC_ACTION_CLEAR:
1970 list_for_each_entry_safe(n, nn, &acg->acn_list,
1972 __scst_acg_remove_acn(n);
1974 scst_check_reassign_sessions();
1979 mutex_unlock(&scst_mutex);
1982 scst_resume_activity();
1985 free_page((unsigned long)buffer);
1991 TRACE_EXIT_RES(res);
1995 static int scst_version_info_show(struct seq_file *seq, void *v)
1999 seq_printf(seq, "%s\n", SCST_VERSION_STRING);
2001 #ifdef CONFIG_SCST_STRICT_SERIALIZING
2002 seq_printf(seq, "Strict serializing enabled\n");
2005 #ifdef CONFIG_SCST_EXTRACHECKS
2006 seq_printf(seq, "EXTRACHECKS\n");
2009 #ifdef CONFIG_SCST_TRACING
2010 seq_printf(seq, "TRACING\n");
2013 #ifdef CONFIG_SCST_DEBUG
2014 seq_printf(seq, "DEBUG\n");
2017 #ifdef CONFIG_SCST_DEBUG_TM
2018 seq_printf(seq, "DEBUG_TM\n");
2021 #ifdef CONFIG_SCST_DEBUG_RETRY
2022 seq_printf(seq, "DEBUG_RETRY\n");
2025 #ifdef CONFIG_SCST_DEBUG_OOM
2026 seq_printf(seq, "DEBUG_OOM\n");
2029 #ifdef CONFIG_SCST_DEBUG_SN
2030 seq_printf(seq, "DEBUG_SN\n");
2033 #ifdef CONFIG_SCST_USE_EXPECTED_VALUES
2034 seq_printf(seq, "USE_EXPECTED_VALUES\n");
2037 #ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
2038 seq_printf(seq, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
2041 #ifdef CONFIG_SCST_STRICT_SECURITY
2042 seq_printf(seq, "SCST_STRICT_SECURITY\n");
2049 static struct scst_proc_data scst_version_proc_data = {
2050 SCST_DEF_RW_SEQ_OP(NULL)
2051 .show = scst_version_info_show,
2054 static int scst_help_info_show(struct seq_file *seq, void *v)
2058 seq_printf(seq, "%s\n", scst_proc_help_string);
2064 static struct scst_proc_data scst_help_proc_data = {
2065 SCST_DEF_RW_SEQ_OP(NULL)
2066 .show = scst_help_info_show,
2069 static int scst_dev_handler_type_info_show(struct seq_file *seq, void *v)
2071 struct scst_dev_type *dev_type = (struct scst_dev_type *)seq->private;
2075 seq_printf(seq, "%d - %s\n", dev_type->type,
2076 dev_type->type > (int)ARRAY_SIZE(scst_proc_dev_handler_type)
2077 ? "unknown" : scst_proc_dev_handler_type[dev_type->type]);
2083 static struct scst_proc_data scst_dev_handler_type_proc_data = {
2084 SCST_DEF_RW_SEQ_OP(NULL)
2085 .show = scst_dev_handler_type_info_show,
2088 static int scst_sessions_info_show(struct seq_file *seq, void *v)
2091 struct scst_acg *acg;
2092 struct scst_session *sess;
2096 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2101 seq_printf(seq, "%-20s %-45s %-35s %-15s\n",
2102 "Target name", "Initiator name",
2103 "Group name", "Command Count");
2105 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
2106 list_for_each_entry(sess, &acg->acg_sess_list,
2107 acg_sess_list_entry) {
2108 seq_printf(seq, "%-20s %-45s %-35s %-15d\n",
2109 sess->tgt->tgtt->name,
2110 sess->initiator_name,
2112 atomic_read(&sess->sess_cmd_count));
2116 mutex_unlock(&scst_mutex);
2119 TRACE_EXIT_RES(res);
2123 static struct scst_proc_data scst_sessions_proc_data = {
2124 SCST_DEF_RW_SEQ_OP(NULL)
2125 .show = scst_sessions_info_show,
2129 static struct scst_proc_data scst_sgv_proc_data = {
2130 SCST_DEF_RW_SEQ_OP(NULL)
2131 .show = sgv_procinfo_show,
2134 static int scst_groups_names_show(struct seq_file *seq, void *v)
2137 struct scst_acg *acg = (struct scst_acg *)seq->private;
2138 struct scst_acn *name;
2142 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2147 list_for_each_entry(name, &acg->acn_list, acn_list_entry) {
2148 seq_printf(seq, "%s\n", name->name);
2151 mutex_unlock(&scst_mutex);
2154 TRACE_EXIT_RES(res);
2158 static struct scst_proc_data scst_groups_names_proc_data = {
2159 SCST_DEF_RW_SEQ_OP(scst_proc_groups_names_write)
2160 .show = scst_groups_names_show,
2163 static int scst_groups_devices_show(struct seq_file *seq, void *v)
2166 struct scst_acg *acg = (struct scst_acg *)seq->private;
2167 struct scst_acg_dev *acg_dev;
2171 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2176 seq_printf(seq, "%-60s%-13s%s\n", "Device (host:ch:id:lun or name)",
2179 list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
2180 if (acg_dev->dev->virt_id == 0) {
2182 int size = sizeof(conv);
2184 memset(conv, 0, size);
2185 size = snprintf(conv, size, "%d:%d:%d:",
2186 acg_dev->dev->scsi_dev->host->host_no,
2187 acg_dev->dev->scsi_dev->channel,
2188 acg_dev->dev->scsi_dev->id);
2189 seq_printf(seq, "%s", conv);
2192 * For some reason the third string argument always
2193 * shown as NULL, so we have to split it on 2 calls.
2195 sprintf(conv, "%%-%dd%%-13d", 60 - size);
2196 size += seq_printf(seq, conv,
2197 acg_dev->dev->scsi_dev->lun,
2199 seq_printf(seq, "%s\n",
2200 acg_dev->rd_only ? "RO" : "");
2202 seq_printf(seq, "%-60s%-13lld%s\n",
2203 acg_dev->dev->virt_name,
2204 (long long unsigned int)acg_dev->lun,
2205 acg_dev->rd_only ? "RO" : "");
2208 mutex_unlock(&scst_mutex);
2211 TRACE_EXIT_RES(res);
2215 static struct scst_proc_data scst_groups_devices_proc_data = {
2216 SCST_DEF_RW_SEQ_OP(scst_proc_groups_devices_write)
2217 .show = scst_groups_devices_show,
2220 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2222 static int scst_proc_read_tlb(const struct scst_proc_log *tbl,
2223 struct seq_file *seq,
2224 unsigned long log_level, int *first)
2226 const struct scst_proc_log *t = tbl;
2230 if (log_level & t->val) {
2231 seq_printf(seq, "%s%s", *first ? "" : " | ", t->token);
2239 int scst_proc_log_entry_read(struct seq_file *seq, unsigned long log_level,
2240 const struct scst_proc_log *tbl)
2242 int res = 0, first = 1;
2246 scst_proc_read_tlb(scst_proc_trace_tbl, seq, log_level, &first);
2249 scst_proc_read_tlb(tbl, seq, log_level, &first);
2251 seq_printf(seq, "%s\n", first ? "none" : "");
2253 TRACE_EXIT_RES(res);
2256 EXPORT_SYMBOL(scst_proc_log_entry_read);
2258 static int log_info_show(struct seq_file *seq, void *v)
2264 if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
2269 res = scst_proc_log_entry_read(seq, trace_flag,
2270 scst_proc_local_trace_tbl);
2272 mutex_unlock(&scst_log_mutex);
2275 TRACE_EXIT_RES(res);
2279 static struct scst_proc_data scst_log_proc_data = {
2280 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_log)
2281 .show = log_info_show,
2287 static int scst_tgt_info_show(struct seq_file *seq, void *v)
2290 struct scst_device *dev;
2294 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2299 seq_printf(seq, "%-60s%s\n", "Device (host:ch:id:lun or name)",
2301 list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
2302 if (dev->virt_id == 0) {
2304 int size = sizeof(conv);
2305 size = snprintf(conv, size, "%d:%d:%d:",
2306 dev->scsi_dev->host->host_no,
2307 dev->scsi_dev->channel,
2309 seq_printf(seq, "%s", conv);
2310 sprintf(conv, "%%-%dd%%s\n", 60 - size);
2311 seq_printf(seq, conv, dev->scsi_dev->lun,
2312 dev->handler ? dev->handler->name : "-");
2314 seq_printf(seq, "%-60s%s\n",
2315 dev->virt_name, dev->handler->name);
2318 mutex_unlock(&scst_mutex);
2321 TRACE_EXIT_RES(res);
2325 static struct scst_proc_data scst_tgt_proc_data = {
2326 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write)
2327 .show = scst_tgt_info_show,
2330 static int scst_threads_info_show(struct seq_file *seq, void *v)
2334 seq_printf(seq, "%d\n", scst_global_threads_count());
2340 static struct scst_proc_data scst_threads_proc_data = {
2341 SCST_DEF_RW_SEQ_OP(scst_proc_threads_write)
2342 .show = scst_threads_info_show,
2345 static int scst_scsi_tgtinfo_show(struct seq_file *seq, void *v)
2347 struct scst_tgt *vtt = seq->private;
2352 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2357 if (vtt->tgtt->read_proc)
2358 res = vtt->tgtt->read_proc(seq, vtt);
2360 mutex_unlock(&scst_proc_mutex);
2362 TRACE_EXIT_RES(res);
2366 static struct scst_proc_data scst_scsi_tgt_proc_data = {
2367 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_write)
2368 .show = scst_scsi_tgtinfo_show,
2371 static int scst_dev_handler_info_show(struct seq_file *seq, void *v)
2373 struct scst_dev_type *dev_type = seq->private;
2378 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2383 if (dev_type->read_proc)
2384 res = dev_type->read_proc(seq, dev_type);
2386 mutex_unlock(&scst_proc_mutex);
2389 TRACE_EXIT_RES(res);
2393 static struct scst_proc_data scst_dev_handler_proc_data = {
2394 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_dev_handler_write)
2395 .show = scst_dev_handler_info_show,
2398 struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry *root,
2399 const char *name, struct scst_proc_data *pdata)
2401 struct proc_dir_entry *p = NULL;
2408 mode = S_IFREG | S_IRUGO | (pdata->seq_op.write ? S_IWUSR : 0);
2409 p = create_proc_entry(name, mode, root);
2411 PRINT_ERROR("Fail to create entry %s in /proc", name);
2413 p->proc_fops = &pdata->seq_op;
2414 p->data = pdata->data;
2421 EXPORT_SYMBOL(scst_create_proc_entry);
2423 int scst_single_seq_open(struct inode *inode, struct file *file)
2425 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
2426 struct scst_proc_data *pdata = container_of(PDE(inode)->proc_fops,
2427 struct scst_proc_data, seq_op);
2429 struct scst_proc_data *pdata = container_of(inode->i_fop,
2430 struct scst_proc_data, seq_op);
2432 return single_open(file, pdata->show, PDE(inode)->data);
2434 EXPORT_SYMBOL(scst_single_seq_open);