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_ADD 4
79 #define SCST_PROC_ACTION_CLEAR 5
80 #define SCST_PROC_ACTION_MOVE 6
81 #define SCST_PROC_ACTION_DEL 7
82 #define SCST_PROC_ACTION_REPLACE 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_trace_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 #ifndef GENERATING_UPSTREAM_PATCH
103 { TRACE_ENTRYEXIT, "entryexit" },
105 { TRACE_PID, "pid" },
106 { TRACE_LINE, "line" },
107 { TRACE_FUNCTION, "function" },
108 { TRACE_DEBUG, "debug" },
109 { TRACE_SPECIAL, "special" },
110 { TRACE_SCSI, "scsi" },
111 { TRACE_MGMT, "mgmt" },
112 { TRACE_MGMT_MINOR, "mgmt_minor" },
113 { TRACE_MGMT_DEBUG, "mgmt_dbg" },
117 static struct scst_trace_log scst_proc_local_trace_tbl[] =
119 { TRACE_RTRY, "retry" },
120 { TRACE_SCSI_SERIALIZING, "scsi_serializing" },
121 { TRACE_RCV_BOT, "recv_bot" },
122 { TRACE_SND_BOT, "send_bot" },
123 { TRACE_RCV_TOP, "recv_top" },
124 { TRACE_SND_TOP, "send_top" },
129 static char *scst_proc_help_string =
130 " echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
132 " echo \"add_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
133 " echo \"del_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
134 " echo \"rename_group OLD_NAME NEW_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
136 " echo \"add|del H:C:I:L lun [READ_ONLY]\""
137 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
138 " echo \"replace H:C:I:L lun [READ_ONLY]\""
139 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
140 " echo \"add|del V_NAME lun [READ_ONLY]\""
141 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
142 " echo \"replace V_NAME lun [READ_ONLY]\""
143 " >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
144 " echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
146 " echo \"add|del NAME\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n"
147 " echo \"move NAME NEW_GROUP_NAME\" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names\n"
148 " echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n"
150 " echo \"DEC|0xHEX|0OCT\" >/proc/scsi_tgt/threads\n"
151 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
153 " echo \"all|none|default\" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
154 " echo \"value DEC|0xHEX|0OCT\""
155 " >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
156 " echo \"set|add|del TOKEN\""
157 " >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
158 " where TOKEN is one of [debug, function, line, pid, entryexit,\n"
159 " buff, mem, sg, out_of_mem, special, scsi,\n"
160 " mgmt, minor, mgmt_minor, mgmt_dbg]\n"
161 " Additionally for /proc/scsi_tgt/trace_level there are these TOKENs\n"
162 " [scsi_serializing, retry, recv_bot, send_bot, recv_top, send_top]\n"
166 static char *scst_proc_dev_handler_type[] =
168 "Direct-access device (e.g., magnetic disk)",
169 "Sequential-access device (e.g., magnetic tape)",
172 "Write-once device (e.g., some optical disks)",
174 "Scanner device (obsolete)",
175 "Optical memory device (e.g., some optical disks)",
176 "Medium changer device (e.g., jukeboxes)",
177 "Communications device (obsolete)",
178 "Defined by ASC IT8 (Graphic arts pre-press devices)",
179 "Defined by ASC IT8 (Graphic arts pre-press devices)",
180 "Storage array controller device (e.g., RAID)",
181 "Enclosure services device",
182 "Simplified direct-access device (e.g., magnetic disk)",
183 "Optical card reader/writer device"
186 static DEFINE_MUTEX(scst_proc_mutex);
188 #include <linux/ctype.h>
190 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3)
191 #if !defined(CONFIG_PPC)
193 * If strcasecmp() and strncasecmp() have already been declared in
194 * <linux/string.h>, do not redefine these functions. Declarations for these
195 * functions are present in the <linux/string.h> header of the following
197 * - The PPC kernel headers for all kernel versions supported by SCST.
198 * - Kernel version 2.6.22 and later for all architectures.
199 * - RHEL 5.3 and later.
201 * Notes about the above preprocessor statement:
202 * - We can't use RHEL_RELEASE_CODE(5, 3) because it would trigger an error on
203 * non-RHEL/CentOS systems -- this expression would expand to "(5,3)".
204 * - There is no space between the minus sign and the zero in the expression
205 * "RHEL_RELEASE_CODE -0" such that it expands to a syntactically valid
206 * expression on non-RHEL/CentOS systems ("-0").
207 * - The above statement has been put on one long line because as of r800
208 * scripts/specialize-patch does not yet handle multi-line preprocessor
209 * statements correctly.
212 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
213 static int strcasecmp(const char *s1, const char *s2)
219 } while (c1 == c2 && c1 != 0);
224 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
225 static int strncasecmp(const char *s1, const char *s2, int n)
227 static int strncasecmp(const char *s1, const char *s2, size_t n)
234 } while ((--n > 0) && c1 == c2 && c1 != 0);
238 #endif /* !CONFIG_PPC */
239 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3) */
241 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
243 static DEFINE_MUTEX(scst_log_mutex);
245 int scst_proc_log_entry_write(struct file *file, const char __user *buf,
246 unsigned long length, unsigned long *log_level,
247 unsigned long default_level, const struct scst_trace_log *tbl)
251 unsigned long level = 0, oldlevel;
252 char *buffer, *p, *e;
253 const struct scst_trace_log *t;
254 char *data = (char *)PDE(file->f_dentry->d_inode)->data;
258 if (length > SCST_PROC_BLOCK_SIZE) {
266 buffer = (char *)__get_free_page(GFP_KERNEL);
271 if (copy_from_user(buffer, buf, length)) {
275 if (length < PAGE_SIZE) {
276 buffer[length] = '\0';
277 } else if (buffer[PAGE_SIZE-1]) {
284 * echo "all|none|default" >/proc/scsi_tgt/trace_level
285 * echo "value DEC|0xHEX|0OCT" >/proc/scsi_tgt/trace_level
286 * echo "add|del TOKEN" >/proc/scsi_tgt/trace_level
289 if (!strncasecmp("all", p, 3)) {
290 action = SCST_PROC_ACTION_ALL;
291 } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) {
292 action = SCST_PROC_ACTION_NONE;
293 } else if (!strncasecmp("default", p, 7)) {
294 action = SCST_PROC_ACTION_DEFAULT;
295 } else if (!strncasecmp("add ", p, 4)) {
297 action = SCST_PROC_ACTION_ADD;
298 } else if (!strncasecmp("del ", p, 4)) {
300 action = SCST_PROC_ACTION_DEL;
301 } else if (!strncasecmp("value ", p, 6)) {
303 action = SCST_PROC_ACTION_VALUE;
305 if (p[strlen(p) - 1] == '\n')
306 p[strlen(p) - 1] = '\0';
307 PRINT_ERROR("Unknown action \"%s\"", p);
313 case SCST_PROC_ACTION_ALL:
316 case SCST_PROC_ACTION_DEFAULT:
317 level = default_level;
319 case SCST_PROC_ACTION_NONE:
322 case SCST_PROC_ACTION_ADD:
323 case SCST_PROC_ACTION_DEL:
324 while (isspace(*p) && *p != '\0')
327 while (!isspace(*e) && *e != '\0')
333 if (!strcasecmp(p, t->token)) {
341 t = scst_proc_trace_tbl;
343 if (!strcasecmp(p, t->token)) {
351 PRINT_ERROR("Unknown token \"%s\"", p);
356 case SCST_PROC_ACTION_VALUE:
357 while (isspace(*p) && *p != '\0')
359 level = simple_strtoul(p, NULL, 0);
363 oldlevel = *log_level;
366 case SCST_PROC_ACTION_ADD:
369 case SCST_PROC_ACTION_DEL:
370 *log_level &= ~level;
377 PRINT_INFO("Changed trace level for \"%s\": "
378 "old 0x%08lx, new 0x%08lx",
379 (char *)data, oldlevel, *log_level);
382 free_page((unsigned long)buffer);
387 EXPORT_SYMBOL(scst_proc_log_entry_write);
389 static ssize_t scst_proc_scsi_tgt_gen_write_log(struct file *file,
390 const char __user *buf,
391 size_t length, loff_t *off)
397 if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
402 res = scst_proc_log_entry_write(file, buf, length,
403 &trace_flag, SCST_DEFAULT_LOG_FLAGS,
404 scst_proc_local_trace_tbl);
406 mutex_unlock(&scst_log_mutex);
413 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
415 #ifdef CONFIG_SCST_MEASURE_LATENCY
417 static char *scst_io_size_names[] = { "<=8K ",
423 static int lat_info_show(struct seq_file *seq, void *v)
426 struct scst_acg *acg;
427 struct scst_session *sess;
432 BUILD_BUG_ON(SCST_LATENCY_STATS_NUM != ARRAY_SIZE(scst_io_size_names));
433 BUILD_BUG_ON(SCST_LATENCY_STATS_NUM != ARRAY_SIZE(sess->sess_latency_stat));
435 if (mutex_lock_interruptible(&scst_mutex) != 0) {
440 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
441 bool header_printed = false;
443 list_for_each_entry(sess, &acg->acg_sess_list,
444 acg_sess_list_entry) {
447 uint64_t scst_time, tgt_time, dev_time;
448 unsigned int processed_cmds;
450 if (!header_printed) {
451 seq_printf(seq, "%-15s %-15s %-46s %-46s %-46s\n",
452 "T-L names", "Total commands", "SCST latency",
453 "Target latency", "Dev latency (min/avg/max/all ns)");
454 header_printed = true;
457 seq_printf(seq, "Target name: %s\nInitiator name: %s\n",
458 sess->tgt->tgtt->name,
459 sess->initiator_name);
461 spin_lock_bh(&sess->lat_lock);
463 for (i = 0; i < SCST_LATENCY_STATS_NUM ; i++) {
464 uint64_t scst_time_wr, tgt_time_wr, dev_time_wr;
465 unsigned int processed_cmds_wr;
466 uint64_t scst_time_rd, tgt_time_rd, dev_time_rd;
467 unsigned int processed_cmds_rd;
468 struct scst_ext_latency_stat *latency_stat;
470 latency_stat = &sess->sess_latency_stat[i];
471 scst_time_wr = latency_stat->scst_time_wr;
472 scst_time_rd = latency_stat->scst_time_rd;
473 tgt_time_wr = latency_stat->tgt_time_wr;
474 tgt_time_rd = latency_stat->tgt_time_rd;
475 dev_time_wr = latency_stat->dev_time_wr;
476 dev_time_rd = latency_stat->dev_time_rd;
477 processed_cmds_wr = latency_stat->processed_cmds_wr;
478 processed_cmds_rd = latency_stat->processed_cmds_rd;
480 seq_printf(seq, "%-5s %-9s %-15lu ",
481 "Write", scst_io_size_names[i],
482 (unsigned long)processed_cmds_wr);
483 if (processed_cmds_wr == 0)
484 processed_cmds_wr = 1;
486 do_div(scst_time_wr, processed_cmds_wr);
487 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
488 (unsigned long)latency_stat->min_scst_time_wr,
489 (unsigned long)scst_time_wr,
490 (unsigned long)latency_stat->max_scst_time_wr,
491 (unsigned long)latency_stat->scst_time_wr);
492 seq_printf(seq, "%-47s", buf);
494 do_div(tgt_time_wr, processed_cmds_wr);
495 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
496 (unsigned long)latency_stat->min_tgt_time_wr,
497 (unsigned long)tgt_time_wr,
498 (unsigned long)latency_stat->max_tgt_time_wr,
499 (unsigned long)latency_stat->tgt_time_wr);
500 seq_printf(seq, "%-47s", buf);
502 do_div(dev_time_wr, processed_cmds_wr);
503 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
504 (unsigned long)latency_stat->min_dev_time_wr,
505 (unsigned long)dev_time_wr,
506 (unsigned long)latency_stat->max_dev_time_wr,
507 (unsigned long)latency_stat->dev_time_wr);
508 seq_printf(seq, "%-47s\n", buf);
510 seq_printf(seq, "%-5s %-9s %-15lu ",
511 "Read", scst_io_size_names[i],
512 (unsigned long)processed_cmds_rd);
513 if (processed_cmds_rd == 0)
514 processed_cmds_rd = 1;
516 do_div(scst_time_rd, processed_cmds_rd);
517 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
518 (unsigned long)latency_stat->min_scst_time_rd,
519 (unsigned long)scst_time_rd,
520 (unsigned long)latency_stat->max_scst_time_rd,
521 (unsigned long)latency_stat->scst_time_rd);
522 seq_printf(seq, "%-47s", buf);
524 do_div(tgt_time_rd, processed_cmds_rd);
525 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
526 (unsigned long)latency_stat->min_tgt_time_rd,
527 (unsigned long)tgt_time_rd,
528 (unsigned long)latency_stat->max_tgt_time_rd,
529 (unsigned long)latency_stat->tgt_time_rd);
530 seq_printf(seq, "%-47s", buf);
532 do_div(dev_time_rd, processed_cmds_rd);
533 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
534 (unsigned long)latency_stat->min_dev_time_rd,
535 (unsigned long)dev_time_rd,
536 (unsigned long)latency_stat->max_dev_time_rd,
537 (unsigned long)latency_stat->dev_time_rd);
538 seq_printf(seq, "%-47s\n", buf);
541 for (t = TGT_DEV_HASH_SIZE-1; t >= 0; t--) {
542 struct list_head *sess_tgt_dev_list_head =
543 &sess->sess_tgt_dev_list_hash[t];
544 struct scst_tgt_dev *tgt_dev;
545 list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
546 sess_tgt_dev_list_entry) {
548 seq_printf(seq, "\nLUN: %llu\n", tgt_dev->lun);
550 for (i = 0; i < SCST_LATENCY_STATS_NUM ; i++) {
551 uint64_t scst_time_wr, tgt_time_wr, dev_time_wr;
552 unsigned int processed_cmds_wr;
553 uint64_t scst_time_rd, tgt_time_rd, dev_time_rd;
554 unsigned int processed_cmds_rd;
555 struct scst_ext_latency_stat *latency_stat;
557 latency_stat = &tgt_dev->dev_latency_stat[i];
558 scst_time_wr = latency_stat->scst_time_wr;
559 scst_time_rd = latency_stat->scst_time_rd;
560 tgt_time_wr = latency_stat->tgt_time_wr;
561 tgt_time_rd = latency_stat->tgt_time_rd;
562 dev_time_wr = latency_stat->dev_time_wr;
563 dev_time_rd = latency_stat->dev_time_rd;
564 processed_cmds_wr = latency_stat->processed_cmds_wr;
565 processed_cmds_rd = latency_stat->processed_cmds_rd;
567 seq_printf(seq, "%-5s %-9s %-15lu ",
568 "Write", scst_io_size_names[i],
569 (unsigned long)processed_cmds_wr);
570 if (processed_cmds_wr == 0)
571 processed_cmds_wr = 1;
573 do_div(scst_time_wr, processed_cmds_wr);
574 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
575 (unsigned long)latency_stat->min_scst_time_wr,
576 (unsigned long)scst_time_wr,
577 (unsigned long)latency_stat->max_scst_time_wr,
578 (unsigned long)latency_stat->scst_time_wr);
579 seq_printf(seq, "%-47s", buf);
581 do_div(tgt_time_wr, processed_cmds_wr);
582 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
583 (unsigned long)latency_stat->min_tgt_time_wr,
584 (unsigned long)tgt_time_wr,
585 (unsigned long)latency_stat->max_tgt_time_wr,
586 (unsigned long)latency_stat->tgt_time_wr);
587 seq_printf(seq, "%-47s", buf);
589 do_div(dev_time_wr, processed_cmds_wr);
590 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
591 (unsigned long)latency_stat->min_dev_time_wr,
592 (unsigned long)dev_time_wr,
593 (unsigned long)latency_stat->max_dev_time_wr,
594 (unsigned long)latency_stat->dev_time_wr);
595 seq_printf(seq, "%-47s\n", buf);
597 seq_printf(seq, "%-5s %-9s %-15lu ",
598 "Read", scst_io_size_names[i],
599 (unsigned long)processed_cmds_rd);
600 if (processed_cmds_rd == 0)
601 processed_cmds_rd = 1;
603 do_div(scst_time_rd, processed_cmds_rd);
604 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
605 (unsigned long)latency_stat->min_scst_time_rd,
606 (unsigned long)scst_time_rd,
607 (unsigned long)latency_stat->max_scst_time_rd,
608 (unsigned long)latency_stat->scst_time_rd);
609 seq_printf(seq, "%-47s", buf);
611 do_div(tgt_time_rd, processed_cmds_rd);
612 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
613 (unsigned long)latency_stat->min_tgt_time_rd,
614 (unsigned long)tgt_time_rd,
615 (unsigned long)latency_stat->max_tgt_time_rd,
616 (unsigned long)latency_stat->tgt_time_rd);
617 seq_printf(seq, "%-47s", buf);
619 do_div(dev_time_rd, processed_cmds_rd);
620 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
621 (unsigned long)latency_stat->min_dev_time_rd,
622 (unsigned long)dev_time_rd,
623 (unsigned long)latency_stat->max_dev_time_rd,
624 (unsigned long)latency_stat->dev_time_rd);
625 seq_printf(seq, "%-47s\n", buf);
630 scst_time = sess->scst_time;
631 tgt_time = sess->tgt_time;
632 dev_time = sess->dev_time;
633 processed_cmds = sess->processed_cmds;
635 seq_printf(seq, "\n%-15s %-16d", "Overall ",
638 if (processed_cmds == 0)
641 do_div(scst_time, processed_cmds);
642 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
643 (unsigned long)sess->min_scst_time,
644 (unsigned long)scst_time,
645 (unsigned long)sess->max_scst_time,
646 (unsigned long)sess->scst_time);
647 seq_printf(seq, "%-47s", buf);
649 do_div(tgt_time, processed_cmds);
650 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
651 (unsigned long)sess->min_tgt_time,
652 (unsigned long)tgt_time,
653 (unsigned long)sess->max_tgt_time,
654 (unsigned long)sess->tgt_time);
655 seq_printf(seq, "%-47s", buf);
657 do_div(dev_time, processed_cmds);
658 snprintf(buf, sizeof(buf), "%lu/%lu/%lu/%lu",
659 (unsigned long)sess->min_dev_time,
660 (unsigned long)dev_time,
661 (unsigned long)sess->max_dev_time,
662 (unsigned long)sess->dev_time);
663 seq_printf(seq, "%-47s\n\n", buf);
665 spin_unlock_bh(&sess->lat_lock);
669 mutex_unlock(&scst_mutex);
676 static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file,
677 const char __user *buf,
678 size_t length, loff_t *off)
681 struct scst_acg *acg;
682 struct scst_session *sess;
686 if (mutex_lock_interruptible(&scst_mutex) != 0) {
691 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
692 list_for_each_entry(sess, &acg->acg_sess_list,
693 acg_sess_list_entry) {
694 PRINT_INFO("Zeroing latency statistics for initiator "
695 "%s", sess->initiator_name);
696 spin_lock_bh(&sess->lat_lock);
701 sess->min_scst_time = 0;
702 sess->min_tgt_time = 0;
703 sess->min_dev_time = 0;
704 sess->max_scst_time = 0;
705 sess->max_tgt_time = 0;
706 sess->max_dev_time = 0;
707 sess->processed_cmds = 0;
708 memset(sess->sess_latency_stat, 0,
709 sizeof(sess->sess_latency_stat));
711 for (t = TGT_DEV_HASH_SIZE-1; t >= 0; t--) {
712 struct list_head *sess_tgt_dev_list_head =
713 &sess->sess_tgt_dev_list_hash[t];
714 struct scst_tgt_dev *tgt_dev;
715 list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
716 sess_tgt_dev_list_entry) {
717 tgt_dev->scst_time = 0;
718 tgt_dev->tgt_time = 0;
719 tgt_dev->dev_time = 0;
720 tgt_dev->processed_cmds = 0;
721 memset(tgt_dev->dev_latency_stat, 0,
722 sizeof(tgt_dev->dev_latency_stat));
726 spin_unlock_bh(&sess->lat_lock);
730 mutex_unlock(&scst_mutex);
737 static struct scst_proc_data scst_lat_proc_data = {
738 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_lat)
739 .show = lat_info_show,
743 #endif /* CONFIG_SCST_MEASURE_LATENCY */
745 static int __init scst_proc_init_module_log(void)
748 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) || \
749 defined(CONFIG_SCST_MEASURE_LATENCY)
750 struct proc_dir_entry *generic;
755 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
756 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
757 SCST_PROC_LOG_ENTRY_NAME,
758 &scst_log_proc_data);
760 PRINT_ERROR("cannot init /proc/%s/%s",
761 SCST_PROC_ENTRY_NAME, SCST_PROC_LOG_ENTRY_NAME);
766 #ifdef CONFIG_SCST_MEASURE_LATENCY
768 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
769 SCST_PROC_LAT_ENTRY_NAME,
770 &scst_lat_proc_data);
772 PRINT_ERROR("cannot init /proc/%s/%s",
773 SCST_PROC_ENTRY_NAME,
774 SCST_PROC_LAT_ENTRY_NAME);
784 static void scst_proc_cleanup_module_log(void)
788 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
789 remove_proc_entry(SCST_PROC_LOG_ENTRY_NAME, scst_proc_scsi_tgt);
792 #ifdef CONFIG_SCST_MEASURE_LATENCY
793 remove_proc_entry(SCST_PROC_LAT_ENTRY_NAME, scst_proc_scsi_tgt);
800 static int scst_proc_group_add_tree(struct scst_acg *acg, const char *name)
803 struct proc_dir_entry *generic;
807 acg->acg_proc_root = proc_mkdir(name, scst_proc_groups_root);
808 if (acg->acg_proc_root == NULL) {
809 PRINT_ERROR("Not enough memory to register %s entry in "
810 "/proc/%s/%s", name, SCST_PROC_ENTRY_NAME,
811 SCST_PROC_GROUPS_ENTRY_NAME);
815 scst_groups_devices_proc_data.data = acg;
816 generic = scst_create_proc_entry(acg->acg_proc_root,
817 SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
818 &scst_groups_devices_proc_data);
820 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
821 SCST_PROC_ENTRY_NAME,
822 SCST_PROC_GROUPS_ENTRY_NAME,
823 name, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME);
828 scst_groups_names_proc_data.data = acg;
829 generic = scst_create_proc_entry(acg->acg_proc_root,
830 SCST_PROC_GROUPS_USERS_ENTRY_NAME,
831 &scst_groups_names_proc_data);
833 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
834 SCST_PROC_ENTRY_NAME,
835 SCST_PROC_GROUPS_ENTRY_NAME,
836 name, SCST_PROC_GROUPS_USERS_ENTRY_NAME);
846 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
850 remove_proc_entry(name, scst_proc_groups_root);
854 static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
859 remove_proc_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME, acg_proc_root);
860 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
862 remove_proc_entry(name, scst_proc_groups_root);
868 /* The activity supposed to be suspended and scst_mutex held */
869 static int scst_proc_group_add(const char *p)
871 int res = 0, len = strlen(p) + 1;
872 struct scst_acg *acg;
877 name = kmalloc(len, GFP_KERNEL);
879 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of name failed");
882 strncpy(name, p, len);
884 acg = scst_alloc_add_acg(name);
886 PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", name);
890 res = scst_proc_group_add_tree(acg, p);
899 scst_proc_del_free_acg(acg, 0);
909 /* The activity supposed to be suspended and scst_mutex held */
910 static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc)
913 struct proc_dir_entry *acg_proc_root = acg->acg_proc_root;
918 if (acg != scst_default_acg) {
919 name = acg->acg_name;
920 res = scst_destroy_acg(acg);
923 scst_proc_del_acg_tree(acg_proc_root, name);
932 /* The activity supposed to be suspended and scst_mutex held */
933 static int scst_proc_rename_acg(struct scst_acg *acg, const char *new_name)
935 int res = 0, len = strlen(new_name) + 1;
937 struct proc_dir_entry *old_acg_proc_root = acg->acg_proc_root;
941 name = kmalloc(len, GFP_KERNEL);
943 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of new name failed");
946 strncpy(name, new_name, len);
948 res = scst_proc_group_add_tree(acg, new_name);
952 scst_proc_del_acg_tree(old_acg_proc_root, acg->acg_name);
954 kfree(acg->acg_name);
955 acg->acg_name = name;
957 scst_check_reassign_sessions();
971 static int __init scst_proc_init_groups(void)
977 /* create the proc directory entry for the device */
978 scst_proc_groups_root = proc_mkdir(SCST_PROC_GROUPS_ENTRY_NAME,
980 if (scst_proc_groups_root == NULL) {
981 PRINT_ERROR("Not enough memory to register %s entry in "
982 "/proc/%s", SCST_PROC_GROUPS_ENTRY_NAME,
983 SCST_PROC_ENTRY_NAME);
987 res = scst_proc_group_add_tree(scst_default_acg,
988 SCST_DEFAULT_ACG_NAME);
997 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
1004 static void scst_proc_cleanup_groups(void)
1006 struct scst_acg *acg_tmp, *acg;
1010 /* remove all groups (dir & entries) */
1011 list_for_each_entry_safe(acg, acg_tmp, &scst_acg_list,
1012 scst_acg_list_entry) {
1013 scst_proc_del_free_acg(acg, 1);
1016 scst_proc_del_acg_tree(scst_default_acg->acg_proc_root,
1017 SCST_DEFAULT_ACG_NAME);
1018 TRACE_DBG("remove_proc_entry(%s, %p)",
1019 SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
1020 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
1025 static int __init scst_proc_init_sgv(void)
1028 struct proc_dir_entry *pr;
1032 pr = scst_create_proc_entry(scst_proc_scsi_tgt, "sgv",
1033 &scst_sgv_proc_data);
1035 PRINT_ERROR("%s", "cannot create sgv /proc entry");
1039 TRACE_EXIT_RES(res);
1043 static void __exit scst_proc_cleanup_sgv(void)
1046 remove_proc_entry("sgv", scst_proc_scsi_tgt);
1050 int __init scst_proc_init_module(void)
1053 struct proc_dir_entry *generic;
1057 scst_proc_scsi_tgt = proc_mkdir(SCST_PROC_ENTRY_NAME, NULL);
1058 if (!scst_proc_scsi_tgt) {
1059 PRINT_ERROR("cannot init /proc/%s", SCST_PROC_ENTRY_NAME);
1063 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
1064 SCST_PROC_ENTRY_NAME,
1065 &scst_tgt_proc_data);
1067 PRINT_ERROR("cannot init /proc/%s/%s",
1068 SCST_PROC_ENTRY_NAME, SCST_PROC_ENTRY_NAME);
1072 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
1073 SCST_PROC_VERSION_NAME,
1074 &scst_version_proc_data);
1076 PRINT_ERROR("cannot init /proc/%s/%s",
1077 SCST_PROC_ENTRY_NAME, SCST_PROC_VERSION_NAME);
1081 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
1082 SCST_PROC_SESSIONS_NAME,
1083 &scst_sessions_proc_data);
1085 PRINT_ERROR("cannot init /proc/%s/%s",
1086 SCST_PROC_ENTRY_NAME, SCST_PROC_SESSIONS_NAME);
1090 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
1091 SCST_PROC_HELP_NAME,
1092 &scst_help_proc_data);
1094 PRINT_ERROR("cannot init /proc/%s/%s",
1095 SCST_PROC_ENTRY_NAME, SCST_PROC_HELP_NAME);
1099 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
1100 SCST_PROC_THREADS_NAME,
1101 &scst_threads_proc_data);
1103 PRINT_ERROR("cannot init /proc/%s/%s",
1104 SCST_PROC_ENTRY_NAME, SCST_PROC_THREADS_NAME);
1108 if (scst_proc_init_module_log() < 0)
1111 if (scst_proc_init_groups() < 0)
1114 if (scst_proc_init_sgv() < 0)
1118 TRACE_EXIT_RES(res);
1122 scst_proc_cleanup_groups();
1125 scst_proc_cleanup_module_log();
1128 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
1131 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
1134 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
1137 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
1140 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
1143 remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
1150 void __exit scst_proc_cleanup_module(void)
1154 /* We may not bother about locks here */
1155 scst_proc_cleanup_sgv();
1156 scst_proc_cleanup_groups();
1157 scst_proc_cleanup_module_log();
1158 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
1159 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
1160 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
1161 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
1162 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
1163 remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
1168 static ssize_t scst_proc_threads_write(struct file *file,
1169 const char __user *buf,
1170 size_t length, loff_t *off)
1173 int oldtn, newtn, delta;
1178 if (length > SCST_PROC_BLOCK_SIZE) {
1186 buffer = (char *)__get_free_page(GFP_KERNEL);
1191 if (copy_from_user(buffer, buf, length)) {
1195 if (length < PAGE_SIZE) {
1196 buffer[length] = '\0';
1197 } else if (buffer[PAGE_SIZE-1]) {
1202 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1207 mutex_lock(&scst_global_threads_mutex);
1209 oldtn = scst_nr_global_threads;
1210 newtn = simple_strtoul(buffer, NULL, 0);
1212 PRINT_ERROR("Illegal threads num value %d", newtn);
1214 goto out_up_thr_free;
1216 delta = newtn - oldtn;
1218 __scst_del_global_threads(-delta);
1220 __scst_add_global_threads(delta);
1222 PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
1225 mutex_unlock(&scst_global_threads_mutex);
1227 mutex_unlock(&scst_proc_mutex);
1230 free_page((unsigned long)buffer);
1232 TRACE_EXIT_RES(res);
1236 int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt)
1242 /* create the proc directory entry for the device */
1243 vtt->proc_tgt_root = proc_mkdir(vtt->name, scst_proc_scsi_tgt);
1244 if (vtt->proc_tgt_root == NULL) {
1245 PRINT_ERROR("Not enough memory to register SCSI target %s "
1246 "in /proc/%s", vtt->name, SCST_PROC_ENTRY_NAME);
1251 TRACE_EXIT_RES(res);
1259 void scst_cleanup_proc_target_dir_entries(struct scst_tgt_template *vtt)
1263 remove_proc_entry(vtt->name, scst_proc_scsi_tgt);
1269 /* Called under scst_mutex */
1270 int scst_build_proc_target_entries(struct scst_tgt *vtt)
1273 struct proc_dir_entry *p;
1278 if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1279 /* create the proc file entry for the device */
1280 scnprintf(name, sizeof(name), "%d", vtt->tgtt->proc_dev_num);
1281 scst_scsi_tgt_proc_data.data = (void *)vtt;
1282 p = scst_create_proc_entry(vtt->tgtt->proc_tgt_root,
1284 &scst_scsi_tgt_proc_data);
1286 PRINT_ERROR("Not enough memory to register SCSI "
1287 "target entry %s in /proc/%s/%s", name,
1288 SCST_PROC_ENTRY_NAME, vtt->tgtt->name);
1292 vtt->proc_num = vtt->tgtt->proc_dev_num;
1293 vtt->tgtt->proc_dev_num++;
1297 TRACE_EXIT_RES(res);
1301 void scst_cleanup_proc_target_entries(struct scst_tgt *vtt)
1307 if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1308 scnprintf(name, sizeof(name), "%d", vtt->proc_num);
1309 remove_proc_entry(name, vtt->tgtt->proc_tgt_root);
1316 static ssize_t scst_proc_scsi_tgt_write(struct file *file,
1317 const char __user *buf,
1318 size_t length, loff_t *off)
1320 struct scst_tgt *vtt =
1321 (struct scst_tgt *)PDE(file->f_dentry->d_inode)->data;
1329 if (vtt->tgtt->write_proc == NULL) {
1334 if (length > SCST_PROC_BLOCK_SIZE) {
1342 buffer = (char *)__get_free_page(GFP_KERNEL);
1347 if (copy_from_user(buffer, buf, length)) {
1351 if (length < PAGE_SIZE) {
1352 buffer[length] = '\0';
1353 } else if (buffer[PAGE_SIZE-1]) {
1358 TRACE_BUFFER("Buffer", buffer, length);
1360 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1365 res = vtt->tgtt->write_proc(buffer, &start, 0, length, &eof, vtt);
1367 mutex_unlock(&scst_proc_mutex);
1370 free_page((unsigned long)buffer);
1372 TRACE_EXIT_RES(res);
1376 int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1379 struct proc_dir_entry *p;
1380 const char *name; /* workaround to keep /proc ABI intact */
1384 sBUG_ON(dev_type->proc_dev_type_root);
1386 if (strcmp(dev_type->name, "vdisk_fileio") == 0)
1389 name = dev_type->name;
1391 /* create the proc directory entry for the dev type handler */
1392 dev_type->proc_dev_type_root = proc_mkdir(name,
1393 scst_proc_scsi_tgt);
1394 if (dev_type->proc_dev_type_root == NULL) {
1395 PRINT_ERROR("Not enough memory to register dev handler dir "
1396 "%s in /proc/%s", name, SCST_PROC_ENTRY_NAME);
1400 scst_dev_handler_type_proc_data.data = dev_type;
1401 if (dev_type->type >= 0) {
1402 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1403 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1404 &scst_dev_handler_type_proc_data);
1406 PRINT_ERROR("Not enough memory to register dev "
1407 "handler entry %s in /proc/%s/%s",
1408 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1409 SCST_PROC_ENTRY_NAME, name);
1414 if (dev_type->read_proc || dev_type->write_proc) {
1415 /* create the proc file entry for the dev type handler */
1416 scst_dev_handler_proc_data.data = (void *)dev_type;
1417 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1419 &scst_dev_handler_proc_data);
1421 PRINT_ERROR("Not enough memory to register dev "
1422 "handler entry %s in /proc/%s/%s", name,
1423 SCST_PROC_ENTRY_NAME, name);
1429 TRACE_EXIT_RES(res);
1433 if (dev_type->type >= 0)
1434 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1435 dev_type->proc_dev_type_root);
1438 remove_proc_entry(name, scst_proc_scsi_tgt);
1445 void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1447 /* Workaround to keep /proc ABI intact */
1452 sBUG_ON(dev_type->proc_dev_type_root == NULL);
1454 if (strcmp(dev_type->name, "vdisk_fileio") == 0)
1457 name = dev_type->name;
1459 if (dev_type->type >= 0) {
1460 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1461 dev_type->proc_dev_type_root);
1463 if (dev_type->read_proc || dev_type->write_proc)
1464 remove_proc_entry(name, dev_type->proc_dev_type_root);
1465 remove_proc_entry(name, scst_proc_scsi_tgt);
1466 dev_type->proc_dev_type_root = NULL;
1472 static ssize_t scst_proc_scsi_dev_handler_write(struct file *file,
1473 const char __user *buf,
1474 size_t length, loff_t *off)
1476 struct scst_dev_type *dev_type =
1477 (struct scst_dev_type *)PDE(file->f_dentry->d_inode)->data;
1485 if (dev_type->write_proc == NULL) {
1490 if (length > SCST_PROC_BLOCK_SIZE) {
1499 buffer = (char *)__get_free_page(GFP_KERNEL);
1505 if (copy_from_user(buffer, buf, length)) {
1509 if (length < PAGE_SIZE) {
1510 buffer[length] = '\0';
1511 } else if (buffer[PAGE_SIZE-1]) {
1516 TRACE_BUFFER("Buffer", buffer, length);
1518 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1523 res = dev_type->write_proc(buffer, &start, 0, length, &eof, dev_type);
1525 mutex_unlock(&scst_proc_mutex);
1528 free_page((unsigned long)buffer);
1531 TRACE_EXIT_RES(res);
1535 static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file,
1536 const char __user *buf,
1537 size_t length, loff_t *off)
1539 int res, rc = 0, action;
1540 char *buffer, *p, *pp;
1541 struct scst_acg *a, *acg = NULL;
1545 if (length > SCST_PROC_BLOCK_SIZE) {
1553 buffer = (char *)__get_free_page(GFP_KERNEL);
1558 if (copy_from_user(buffer, buf, length)) {
1562 if (length < PAGE_SIZE) {
1563 buffer[length] = '\0';
1564 } else if (buffer[PAGE_SIZE-1]) {
1570 * Usage: echo "add_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1571 * or echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1572 * or echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt"
1573 * or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt
1576 if (p[strlen(p) - 1] == '\n')
1577 p[strlen(p) - 1] = '\0';
1578 if (!strncasecmp("assign ", p, 7)) {
1580 action = SCST_PROC_ACTION_ASSIGN;
1581 } else if (!strncasecmp("add_group ", p, 10)) {
1583 action = SCST_PROC_ACTION_ADD_GROUP;
1584 } else if (!strncasecmp("del_group ", p, 10)) {
1586 action = SCST_PROC_ACTION_DEL_GROUP;
1587 } else if (!strncasecmp("rename_group ", p, 13)) {
1589 action = SCST_PROC_ACTION_RENAME_GROUP;
1591 PRINT_ERROR("Unknown action \"%s\"", p);
1596 res = scst_suspend_activity(true);
1600 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1602 goto out_free_resume;
1608 case SCST_PROC_ACTION_ADD_GROUP:
1609 case SCST_PROC_ACTION_DEL_GROUP:
1610 case SCST_PROC_ACTION_RENAME_GROUP:
1612 while (!isspace(*pp) && *pp != '\0')
1617 while (isspace(*pp) && *pp != '\0')
1621 case SCST_PROC_ACTION_ADD_GROUP:
1622 case SCST_PROC_ACTION_DEL_GROUP:
1623 PRINT_ERROR("%s", "Too many "
1631 if (strcmp(p, SCST_DEFAULT_ACG_NAME) == 0) {
1632 PRINT_ERROR("Attempt to add/delete/rename predefined "
1638 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1639 if (strcmp(a->acg_name, p) == 0) {
1640 TRACE_DBG("group (acg) %p %s found",
1648 case SCST_PROC_ACTION_ADD_GROUP:
1650 PRINT_ERROR("acg name %s exist", p);
1654 rc = scst_proc_group_add(p);
1656 case SCST_PROC_ACTION_DEL_GROUP:
1658 PRINT_ERROR("acg name %s not found", p);
1662 rc = scst_proc_del_free_acg(acg, 1);
1664 case SCST_PROC_ACTION_RENAME_GROUP:
1666 PRINT_ERROR("acg name %s not found", p);
1672 while (!isspace(*pp) && *pp != '\0')
1677 while (isspace(*pp) && *pp != '\0')
1680 PRINT_ERROR("%s", "Too many arguments");
1685 rc = scst_proc_rename_acg(acg, p);
1689 case SCST_PROC_ACTION_ASSIGN:
1690 rc = scst_proc_assign_handler(p);
1698 mutex_unlock(&scst_mutex);
1701 scst_resume_activity();
1704 free_page((unsigned long)buffer);
1707 TRACE_EXIT_RES(res);
1711 /* The activity supposed to be suspended and scst_mutex held */
1712 static int scst_proc_assign_handler(char *buf)
1715 char *p = buf, *e, *ee;
1716 unsigned long host, channel = 0, id = 0, lun = 0;
1717 struct scst_device *d, *dev = NULL;
1718 struct scst_dev_type *dt, *handler = NULL;
1722 while (isspace(*p) && *p != '\0')
1725 host = simple_strtoul(p, &p, 0);
1726 if ((host == ULONG_MAX) || (*p != ':'))
1729 channel = simple_strtoul(p, &p, 0);
1730 if ((channel == ULONG_MAX) || (*p != ':'))
1733 id = simple_strtoul(p, &p, 0);
1734 if ((channel == ULONG_MAX) || (*p != ':'))
1737 lun = simple_strtoul(p, &p, 0);
1738 if (lun == ULONG_MAX)
1743 while (isspace(*e) && *e != '\0')
1746 while (!isspace(*ee) && *ee != '\0')
1750 TRACE_DBG("Dev %ld:%ld:%ld:%ld, handler %s", host, channel, id, lun, e);
1752 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1753 if ((d->virt_id == 0) &&
1754 d->scsi_dev->host->host_no == host &&
1755 d->scsi_dev->channel == channel &&
1756 d->scsi_dev->id == id &&
1757 d->scsi_dev->lun == lun) {
1759 TRACE_DBG("Dev %p (%ld:%ld:%ld:%ld) found",
1760 dev, host, channel, id, lun);
1766 PRINT_ERROR("Device %ld:%ld:%ld:%ld not found",
1767 host, channel, id, lun);
1772 list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
1773 if (!strcmp(dt->name, e)) {
1775 TRACE_DBG("Dev handler %p with name %s found",
1781 if (handler == NULL) {
1782 PRINT_ERROR("Handler %s not found", e);
1787 if (dev->scsi_dev->type != handler->type) {
1788 PRINT_ERROR("Type %d of device %s differs from type "
1789 "%d of dev handler %s", dev->type,
1790 dev->handler->name, handler->type, handler->name);
1795 res = scst_assign_dev_handler(dev, handler);
1798 TRACE_EXIT_RES(res);
1802 PRINT_ERROR("Syntax error on %s", p);
1807 static ssize_t scst_proc_groups_devices_write(struct file *file,
1808 const char __user *buf,
1809 size_t length, loff_t *off)
1811 int res, action, virt = 0, rc, read_only = 0;
1812 char *buffer, *p, *e = NULL;
1813 unsigned int host, channel = 0, id = 0, lun = 0, virt_lun;
1814 struct scst_acg *acg =
1815 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1816 struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
1817 struct scst_device *d, *dev = NULL;
1821 if (length > SCST_PROC_BLOCK_SIZE) {
1829 buffer = (char *)__get_free_page(GFP_KERNEL);
1834 if (copy_from_user(buffer, buf, length)) {
1838 if (length < PAGE_SIZE) {
1839 buffer[length] = '\0';
1840 } else if (buffer[PAGE_SIZE-1]) {
1846 * Usage: echo "add|del H:C:I:L lun [READ_ONLY]" \
1847 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1848 * or echo "replace H:C:I:L lun [READ_ONLY]" \
1849 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1850 * or echo "add|del V_NAME lun [READ_ONLY]" \
1851 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1852 * or echo "replace V_NAME lun [READ_ONLY]" \
1853 * >/proc/scsi_tgt/groups/GROUP_NAME/devices
1854 * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/devices
1857 if (p[strlen(p) - 1] == '\n')
1858 p[strlen(p) - 1] = '\0';
1859 if (!strncasecmp("clear", p, 5)) {
1860 action = SCST_PROC_ACTION_CLEAR;
1861 } else if (!strncasecmp("add ", p, 4)) {
1863 action = SCST_PROC_ACTION_ADD;
1864 } else if (!strncasecmp("del ", p, 4)) {
1866 action = SCST_PROC_ACTION_DEL;
1867 } else if (!strncasecmp("replace ", p, 8)) {
1869 action = SCST_PROC_ACTION_REPLACE;
1871 PRINT_ERROR("Unknown action \"%s\"", p);
1876 res = scst_suspend_activity(true);
1880 if (mutex_lock_interruptible(&scst_mutex) != 0) {
1882 goto out_free_resume;
1888 case SCST_PROC_ACTION_ADD:
1889 case SCST_PROC_ACTION_DEL:
1890 case SCST_PROC_ACTION_REPLACE:
1891 while (isspace(*p) && *p != '\0')
1894 host = simple_strtoul(p, &p, 0);
1896 channel = simple_strtoul(p + 1, &p, 0);
1897 id = simple_strtoul(p + 1, &p, 0);
1898 lun = simple_strtoul(p + 1, &p, 0);
1902 p = e; /* restore p */
1903 while (!isspace(*e) && *e != '\0')
1908 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1910 if (d->virt_id && !strcmp(d->virt_name, p)) {
1912 TRACE_DBG("Virt device %p (%s) found",
1918 d->scsi_dev->host->host_no == host &&
1919 d->scsi_dev->channel == channel &&
1920 d->scsi_dev->id == id &&
1921 d->scsi_dev->lun == lun) {
1923 TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
1924 dev, host, channel, id, lun);
1931 PRINT_ERROR("Virt device %s not found", p);
1933 PRINT_ERROR("Device %d:%d:%d:%d not found",
1934 host, channel, id, lun);
1942 /* ToDo: create separate functions */
1945 case SCST_PROC_ACTION_ADD:
1946 case SCST_PROC_ACTION_REPLACE:
1948 bool dev_replaced = false;
1951 while (isspace(*e) && *e != '\0')
1953 virt_lun = simple_strtoul(e, &e, 0);
1955 while (isspace(*e) && *e != '\0')
1959 if (!strncasecmp("READ_ONLY", e, 9))
1962 PRINT_ERROR("Unknown option \"%s\"", e);
1968 list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
1969 acg_dev_list_entry) {
1970 if (acg_dev_tmp->lun == virt_lun) {
1971 acg_dev = acg_dev_tmp;
1975 if (acg_dev != NULL) {
1976 if (action == SCST_PROC_ACTION_ADD) {
1977 PRINT_ERROR("virt lun %d already exists in "
1978 "group %s", virt_lun, acg->acg_name);
1983 rc = scst_acg_remove_dev(acg, acg_dev->dev,
1989 dev_replaced = true;
1993 rc = scst_acg_add_dev(acg, dev, virt_lun, read_only,
1994 action == SCST_PROC_ACTION_ADD);
2001 struct scst_tgt_dev *tgt_dev;
2003 list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
2004 dev_tgt_dev_list_entry) {
2005 if ((tgt_dev->acg_dev->acg == acg) &&
2006 (tgt_dev->lun == virt_lun)) {
2007 TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED"
2008 " on tgt_dev %p", tgt_dev);
2009 scst_gen_aen_or_ua(tgt_dev,
2010 SCST_LOAD_SENSE(scst_sense_inquery_data_changed));
2016 case SCST_PROC_ACTION_DEL:
2017 rc = scst_acg_remove_dev(acg, dev, true);
2023 case SCST_PROC_ACTION_CLEAR:
2024 list_for_each_entry_safe(acg_dev, acg_dev_tmp,
2026 acg_dev_list_entry) {
2027 rc = scst_acg_remove_dev(acg, acg_dev->dev,
2028 list_is_last(&acg_dev->acg_dev_list_entry,
2029 &acg->acg_dev_list));
2039 mutex_unlock(&scst_mutex);
2042 scst_resume_activity();
2045 free_page((unsigned long)buffer);
2048 TRACE_EXIT_RES(res);
2052 static ssize_t scst_proc_groups_names_write(struct file *file,
2053 const char __user *buf,
2054 size_t length, loff_t *off)
2056 int res = length, rc = 0, action;
2057 char *buffer, *p, *pp = NULL;
2058 struct scst_acg *acg =
2059 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
2060 struct scst_acn *n, *nn;
2064 if (length > SCST_PROC_BLOCK_SIZE) {
2072 buffer = (char *)__get_free_page(GFP_KERNEL);
2077 if (copy_from_user(buffer, buf, length)) {
2081 if (length < PAGE_SIZE) {
2082 buffer[length] = '\0';
2083 } else if (buffer[PAGE_SIZE-1]) {
2089 * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP_NAME/names
2090 * or echo "move NAME NEW_GROUP_NAME" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names"
2091 * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/names
2094 if (p[strlen(p) - 1] == '\n')
2095 p[strlen(p) - 1] = '\0';
2096 if (!strncasecmp("clear", p, 5)) {
2097 action = SCST_PROC_ACTION_CLEAR;
2098 } else if (!strncasecmp("add ", p, 4)) {
2100 action = SCST_PROC_ACTION_ADD;
2101 } else if (!strncasecmp("del ", p, 4)) {
2103 action = SCST_PROC_ACTION_DEL;
2104 } else if (!strncasecmp("move ", p, 5)) {
2106 action = SCST_PROC_ACTION_MOVE;
2108 PRINT_ERROR("Unknown action \"%s\"", p);
2114 case SCST_PROC_ACTION_ADD:
2115 case SCST_PROC_ACTION_DEL:
2116 case SCST_PROC_ACTION_MOVE:
2117 while (isspace(*p) && *p != '\0')
2120 while (!isspace(*pp) && *pp != '\0')
2125 while (isspace(*pp) && *pp != '\0')
2129 case SCST_PROC_ACTION_ADD:
2130 case SCST_PROC_ACTION_DEL:
2131 PRINT_ERROR("%s", "Too many "
2141 rc = scst_suspend_activity(true);
2145 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2147 goto out_free_resume;
2151 case SCST_PROC_ACTION_ADD:
2152 rc = scst_acg_add_name(acg, p);
2154 case SCST_PROC_ACTION_DEL:
2155 rc = scst_acg_remove_name(acg, p, true);
2157 case SCST_PROC_ACTION_MOVE:
2159 struct scst_acg *a, *new_acg = NULL;
2162 while (!isspace(*pp) && *pp != '\0')
2167 while (isspace(*pp) && *pp != '\0')
2170 PRINT_ERROR("%s", "Too many arguments");
2172 goto out_free_unlock;
2175 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
2176 if (strcmp(a->acg_name, p) == 0) {
2177 TRACE_DBG("group (acg) %p %s found",
2183 if (new_acg == NULL) {
2184 PRINT_ERROR("Group %s not found", p);
2186 goto out_free_unlock;
2188 rc = scst_acg_remove_name(acg, name, false);
2190 goto out_free_unlock;
2191 rc = scst_acg_add_name(new_acg, name);
2194 case SCST_PROC_ACTION_CLEAR:
2195 list_for_each_entry_safe(n, nn, &acg->acn_list,
2197 __scst_acg_remove_acn(n);
2199 scst_check_reassign_sessions();
2204 mutex_unlock(&scst_mutex);
2207 scst_resume_activity();
2210 free_page((unsigned long)buffer);
2216 TRACE_EXIT_RES(res);
2220 static int scst_version_info_show(struct seq_file *seq, void *v)
2224 seq_printf(seq, "%s\n", SCST_VERSION_STRING);
2226 #ifdef CONFIG_SCST_STRICT_SERIALIZING
2227 seq_printf(seq, "Strict serializing enabled\n");
2230 #ifdef CONFIG_SCST_EXTRACHECKS
2231 seq_printf(seq, "EXTRACHECKS\n");
2234 #ifdef CONFIG_SCST_TRACING
2235 seq_printf(seq, "TRACING\n");
2238 #ifdef CONFIG_SCST_DEBUG
2239 seq_printf(seq, "DEBUG\n");
2242 #ifdef CONFIG_SCST_DEBUG_TM
2243 seq_printf(seq, "DEBUG_TM\n");
2246 #ifdef CONFIG_SCST_DEBUG_RETRY
2247 seq_printf(seq, "DEBUG_RETRY\n");
2250 #ifdef CONFIG_SCST_DEBUG_OOM
2251 seq_printf(seq, "DEBUG_OOM\n");
2254 #ifdef CONFIG_SCST_DEBUG_SN
2255 seq_printf(seq, "DEBUG_SN\n");
2258 #ifdef CONFIG_SCST_USE_EXPECTED_VALUES
2259 seq_printf(seq, "USE_EXPECTED_VALUES\n");
2262 #ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
2263 seq_printf(seq, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
2266 #ifdef CONFIG_SCST_STRICT_SECURITY
2267 seq_printf(seq, "SCST_STRICT_SECURITY\n");
2274 static struct scst_proc_data scst_version_proc_data = {
2275 SCST_DEF_RW_SEQ_OP(NULL)
2276 .show = scst_version_info_show,
2279 static int scst_help_info_show(struct seq_file *seq, void *v)
2283 seq_printf(seq, "%s\n", scst_proc_help_string);
2289 static struct scst_proc_data scst_help_proc_data = {
2290 SCST_DEF_RW_SEQ_OP(NULL)
2291 .show = scst_help_info_show,
2294 static int scst_dev_handler_type_info_show(struct seq_file *seq, void *v)
2296 struct scst_dev_type *dev_type = (struct scst_dev_type *)seq->private;
2300 seq_printf(seq, "%d - %s\n", dev_type->type,
2301 dev_type->type > (int)ARRAY_SIZE(scst_proc_dev_handler_type)
2302 ? "unknown" : scst_proc_dev_handler_type[dev_type->type]);
2308 static struct scst_proc_data scst_dev_handler_type_proc_data = {
2309 SCST_DEF_RW_SEQ_OP(NULL)
2310 .show = scst_dev_handler_type_info_show,
2313 static int scst_sessions_info_show(struct seq_file *seq, void *v)
2316 struct scst_acg *acg;
2317 struct scst_session *sess;
2321 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2326 seq_printf(seq, "%-20s %-45s %-35s %-15s\n",
2327 "Target name", "Initiator name",
2328 "Group name", "Command Count");
2330 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
2331 list_for_each_entry(sess, &acg->acg_sess_list,
2332 acg_sess_list_entry) {
2333 seq_printf(seq, "%-20s %-45s %-35s %-15d\n",
2334 sess->tgt->tgtt->name,
2335 sess->initiator_name,
2337 atomic_read(&sess->sess_cmd_count));
2341 mutex_unlock(&scst_mutex);
2344 TRACE_EXIT_RES(res);
2348 static struct scst_proc_data scst_sessions_proc_data = {
2349 SCST_DEF_RW_SEQ_OP(NULL)
2350 .show = scst_sessions_info_show,
2353 static struct scst_proc_data scst_sgv_proc_data = {
2354 SCST_DEF_RW_SEQ_OP(NULL)
2355 .show = sgv_procinfo_show,
2358 static int scst_groups_names_show(struct seq_file *seq, void *v)
2361 struct scst_acg *acg = (struct scst_acg *)seq->private;
2362 struct scst_acn *name;
2366 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2371 list_for_each_entry(name, &acg->acn_list, acn_list_entry) {
2372 seq_printf(seq, "%s\n", name->name);
2375 mutex_unlock(&scst_mutex);
2378 TRACE_EXIT_RES(res);
2382 static struct scst_proc_data scst_groups_names_proc_data = {
2383 SCST_DEF_RW_SEQ_OP(scst_proc_groups_names_write)
2384 .show = scst_groups_names_show,
2387 static int scst_groups_devices_show(struct seq_file *seq, void *v)
2390 struct scst_acg *acg = (struct scst_acg *)seq->private;
2391 struct scst_acg_dev *acg_dev;
2395 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2400 seq_printf(seq, "%-60s%-13s%s\n", "Device (host:ch:id:lun or name)",
2403 list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
2404 if (acg_dev->dev->virt_id == 0) {
2406 int size = sizeof(conv);
2408 memset(conv, 0, size);
2409 size = snprintf(conv, size, "%d:%d:%d:",
2410 acg_dev->dev->scsi_dev->host->host_no,
2411 acg_dev->dev->scsi_dev->channel,
2412 acg_dev->dev->scsi_dev->id);
2413 seq_printf(seq, "%s", conv);
2416 * For some reason the third string argument always
2417 * shown as NULL, so we have to split it on 2 calls.
2419 sprintf(conv, "%%-%dd%%-13d", 60 - size);
2420 size += seq_printf(seq, conv,
2421 acg_dev->dev->scsi_dev->lun,
2423 seq_printf(seq, "%s\n",
2424 acg_dev->rd_only ? "RO" : "");
2426 seq_printf(seq, "%-60s%-13lld%s\n",
2427 acg_dev->dev->virt_name,
2428 (long long unsigned int)acg_dev->lun,
2429 acg_dev->rd_only ? "RO" : "");
2432 mutex_unlock(&scst_mutex);
2435 TRACE_EXIT_RES(res);
2439 static struct scst_proc_data scst_groups_devices_proc_data = {
2440 SCST_DEF_RW_SEQ_OP(scst_proc_groups_devices_write)
2441 .show = scst_groups_devices_show,
2444 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2446 static int scst_proc_read_tlb(const struct scst_trace_log *tbl,
2447 struct seq_file *seq,
2448 unsigned long log_level, int *first)
2450 const struct scst_trace_log *t = tbl;
2454 if (log_level & t->val) {
2455 seq_printf(seq, "%s%s", *first ? "" : " | ", t->token);
2463 int scst_proc_log_entry_read(struct seq_file *seq, unsigned long log_level,
2464 const struct scst_trace_log *tbl)
2466 int res = 0, first = 1;
2470 scst_proc_read_tlb(scst_proc_trace_tbl, seq, log_level, &first);
2473 scst_proc_read_tlb(tbl, seq, log_level, &first);
2475 seq_printf(seq, "%s\n", first ? "none" : "");
2477 TRACE_EXIT_RES(res);
2480 EXPORT_SYMBOL(scst_proc_log_entry_read);
2482 static int log_info_show(struct seq_file *seq, void *v)
2488 if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
2493 res = scst_proc_log_entry_read(seq, trace_flag,
2494 scst_proc_local_trace_tbl);
2496 mutex_unlock(&scst_log_mutex);
2499 TRACE_EXIT_RES(res);
2503 static struct scst_proc_data scst_log_proc_data = {
2504 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_log)
2505 .show = log_info_show,
2511 static int scst_tgt_info_show(struct seq_file *seq, void *v)
2514 struct scst_device *dev;
2518 if (mutex_lock_interruptible(&scst_mutex) != 0) {
2523 seq_printf(seq, "%-60s%s\n", "Device (host:ch:id:lun or name)",
2525 list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
2526 if (dev->virt_id == 0) {
2528 int size = sizeof(conv);
2529 size = snprintf(conv, size, "%d:%d:%d:",
2530 dev->scsi_dev->host->host_no,
2531 dev->scsi_dev->channel,
2533 seq_printf(seq, "%s", conv);
2534 sprintf(conv, "%%-%dd%%s\n", 60 - size);
2535 seq_printf(seq, conv, dev->scsi_dev->lun,
2536 dev->handler ? dev->handler->name : "-");
2538 seq_printf(seq, "%-60s%s\n",
2539 dev->virt_name, dev->handler->name);
2542 mutex_unlock(&scst_mutex);
2545 TRACE_EXIT_RES(res);
2549 static struct scst_proc_data scst_tgt_proc_data = {
2550 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write)
2551 .show = scst_tgt_info_show,
2554 static int scst_threads_info_show(struct seq_file *seq, void *v)
2558 seq_printf(seq, "%d\n", scst_global_threads_count());
2564 static struct scst_proc_data scst_threads_proc_data = {
2565 SCST_DEF_RW_SEQ_OP(scst_proc_threads_write)
2566 .show = scst_threads_info_show,
2569 static int scst_scsi_tgtinfo_show(struct seq_file *seq, void *v)
2571 struct scst_tgt *vtt = seq->private;
2576 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2581 if (vtt->tgtt->read_proc)
2582 res = vtt->tgtt->read_proc(seq, vtt);
2584 mutex_unlock(&scst_proc_mutex);
2586 TRACE_EXIT_RES(res);
2590 static struct scst_proc_data scst_scsi_tgt_proc_data = {
2591 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_write)
2592 .show = scst_scsi_tgtinfo_show,
2595 static int scst_dev_handler_info_show(struct seq_file *seq, void *v)
2597 struct scst_dev_type *dev_type = seq->private;
2602 if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2607 if (dev_type->read_proc)
2608 res = dev_type->read_proc(seq, dev_type);
2610 mutex_unlock(&scst_proc_mutex);
2613 TRACE_EXIT_RES(res);
2617 static struct scst_proc_data scst_dev_handler_proc_data = {
2618 SCST_DEF_RW_SEQ_OP(scst_proc_scsi_dev_handler_write)
2619 .show = scst_dev_handler_info_show,
2622 struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry *root,
2623 const char *name, struct scst_proc_data *pdata)
2625 struct proc_dir_entry *p = NULL;
2632 mode = S_IFREG | S_IRUGO | (pdata->seq_op.write ? S_IWUSR : 0);
2633 p = create_proc_entry(name, mode, root);
2635 PRINT_ERROR("Fail to create entry %s in /proc", name);
2637 p->proc_fops = &pdata->seq_op;
2638 p->data = pdata->data;
2645 EXPORT_SYMBOL(scst_create_proc_entry);
2647 int scst_single_seq_open(struct inode *inode, struct file *file)
2649 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
2650 struct scst_proc_data *pdata = container_of(PDE(inode)->proc_fops,
2651 struct scst_proc_data, seq_op);
2653 struct scst_proc_data *pdata = container_of(inode->i_fop,
2654 struct scst_proc_data, seq_op);
2656 return single_open(file, pdata->show, PDE(inode)->data);
2658 EXPORT_SYMBOL(scst_single_seq_open);
2660 struct proc_dir_entry *scst_proc_get_tgt_root(
2661 struct scst_tgt_template *vtt)
2663 return vtt->proc_tgt_root;
2665 EXPORT_SYMBOL(scst_proc_get_tgt_root);
2667 struct proc_dir_entry *scst_proc_get_dev_type_root(
2668 struct scst_dev_type *dtt)
2670 return dtt->proc_dev_type_root;
2672 EXPORT_SYMBOL(scst_proc_get_dev_type_root);