- Added "replace" command to replace one LUN by another and generate INQUIRY DATA...
[mirror/scst/.git] / scst / src / scst_proc.c
1 /*
2  *  scst_proc.c
3  *
4  *  Copyright (C) 2004 - 2009 Vladislav Bolkhovitin <vst@vlnb.net>
5  *  Copyright (C) 2004 - 2005 Leonid Stoljar
6  *  Copyright (C) 2007 - 2009 ID7 Ltd.
7  *
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
11  *  of the License.
12  *
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.
17  */
18
19 #include <linux/module.h>
20
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>
32
33 #include "scst.h"
34 #include "scst_priv.h"
35 #include "scst_mem.h"
36
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);
42
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;
54
55 /*
56  * Must be less than 4K page size, since our output routines
57  * use some slack for overruns
58  */
59 #define SCST_PROC_BLOCK_SIZE (PAGE_SIZE - 512)
60
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"
70
71 #ifdef CONFIG_SCST_MEASURE_LATENCY
72 #define SCST_PROC_LAT_ENTRY_NAME                "latency"
73 #endif
74
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
89
90 static struct proc_dir_entry *scst_proc_scsi_tgt;
91 static struct proc_dir_entry *scst_proc_groups_root;
92
93 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
94 static struct scst_proc_data scst_log_proc_data;
95
96 static struct scst_proc_log scst_proc_trace_tbl[] =
97 {
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" },
113     { 0,                        NULL }
114 };
115
116 static struct scst_proc_log scst_proc_local_trace_tbl[] =
117 {
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" },
124     { 0,                        NULL }
125 };
126 #endif
127
128 static char *scst_proc_help_string =
129 "   echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
130 "\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"
134 "\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"
144 "\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"
148 "\n"
149 "   echo \"DEC|0xHEX|0OCT\" >/proc/scsi_tgt/threads\n"
150 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
151 "\n"
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"
161 #endif
162 ;
163
164 static char *scst_proc_dev_handler_type[] =
165 {
166     "Direct-access device (e.g., magnetic disk)",
167     "Sequential-access device (e.g., magnetic tape)",
168     "Printer device",
169     "Processor device",
170     "Write-once device (e.g., some optical disks)",
171     "CD-ROM device",
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"
182 };
183
184 static DEFINE_MUTEX(scst_proc_mutex);
185
186 #include <linux/ctype.h>
187
188 #if !defined(CONFIG_PPC) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3)
189 /*
190  * If strcasecmp() and strncasecmp() have already been declared in
191  * <linux/string.h>, do not redefine these functions. Declarations for these
192  * functions are present in the <linux/string.h> header of the following
193  * kernels:
194  * - The PPC kernel headers for all kernel versions supported by SCST.
195  * - Kernel version 2.6.22 and later for all architectures.
196  * - RHEL 5.3 and later.
197  *
198  * Notes about the above preprocessor statement:
199  * - We can't use RHEL_RELEASE_CODE(5, 3) because it would trigger an error on
200  *   non-RHEL/CentOS systems -- this expression would expand to "(5,3)".
201  * - There is no space between the minus sign and the zero in the expression
202  *   "RHEL_RELEASE_CODE -0" such that it expands to a syntactically valid
203  *   expression on non-RHEL/CentOS systems ("-0").
204  * - The above statement has been put on one long line because as of r800
205  *   scripts/specialize-patch does not yet handle multi-line preprocessor
206  *   statements correctly.
207  */
208
209 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
210 static int strcasecmp(const char *s1, const char *s2)
211 {
212         int c1, c2;
213         do {
214                 c1 = tolower(*s1++);
215                 c2 = tolower(*s2++);
216         } while (c1 == c2 && c1 != 0);
217         return c1 - c2;
218 }
219 #endif
220
221 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
222 static int strncasecmp(const char *s1, const char *s2, int n)
223 #else
224 static int strncasecmp(const char *s1, const char *s2, size_t n)
225 #endif
226 {
227         int c1, c2;
228         do {
229                 c1 = tolower(*s1++);
230                 c2 = tolower(*s2++);
231         } while ((--n > 0) && c1 == c2 && c1 != 0);
232         return c1 - c2;
233 }
234
235 #endif /* !CONFIG_PPC && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) */
236
237 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
238
239 static DEFINE_MUTEX(scst_log_mutex);
240
241 int scst_proc_log_entry_write(struct file *file, const char __user *buf,
242         unsigned long length, unsigned long *log_level,
243         unsigned long default_level, const struct scst_proc_log *tbl)
244 {
245         int res = length;
246         int action;
247         unsigned long level = 0, oldlevel;
248         char *buffer, *p, *e;
249         const struct scst_proc_log *t;
250         char *data = (char *)PDE(file->f_dentry->d_inode)->data;
251
252         TRACE_ENTRY();
253
254         if (length > SCST_PROC_BLOCK_SIZE) {
255                 res = -EOVERFLOW;
256                 goto out;
257         }
258         if (!buf) {
259                 res = -EINVAL;
260                 goto out;
261         }
262         buffer = (char *)__get_free_page(GFP_KERNEL);
263         if (!buffer) {
264                 res = -ENOMEM;
265                 goto out;
266         }
267         if (copy_from_user(buffer, buf, length)) {
268                 res = -EFAULT;
269                 goto out_free;
270         }
271         if (length < PAGE_SIZE) {
272                 buffer[length] = '\0';
273         } else if (buffer[PAGE_SIZE-1]) {
274                 res = -EINVAL;
275                 goto out_free;
276         }
277
278         /*
279          * Usage:
280          *   echo "all|none|default" >/proc/scsi_tgt/trace_level
281          *   echo "value DEC|0xHEX|0OCT" >/proc/scsi_tgt/trace_level
282          *   echo "set|add|clear|del TOKEN" >/proc/scsi_tgt/trace_level
283          * where TOKEN is one of [debug,function,line,pid,entryexit,
284          *                        buff,mem,sg,out_of_mem,retry,
285          *                        scsi_serializing,special,scsi,mgmt,minor,...]
286          */
287         p = buffer;
288         if (!strncasecmp("all", p, 3)) {
289                 action = SCST_PROC_ACTION_ALL;
290         } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) {
291                 action = SCST_PROC_ACTION_NONE;
292         } else if (!strncasecmp("default", p, 7)) {
293                 action = SCST_PROC_ACTION_DEFAULT;
294         } else if (!strncasecmp("set ", p, 4)) {
295                 p += 4;
296                 action = SCST_PROC_ACTION_SET;
297         } else if (!strncasecmp("add ", p, 4)) {
298                 p += 4;
299                 action = SCST_PROC_ACTION_ADD;
300         } else if (!strncasecmp("del ", p, 4)) {
301                 p += 4;
302                 action = SCST_PROC_ACTION_DEL;
303         } else if (!strncasecmp("value ", p, 6)) {
304                 p += 6;
305                 action = SCST_PROC_ACTION_VALUE;
306         } else {
307                 if (p[strlen(p) - 1] == '\n')
308                         p[strlen(p) - 1] = '\0';
309                 PRINT_ERROR("Unknown action \"%s\"", p);
310                 res = -EINVAL;
311                 goto out_free;
312         }
313
314         switch (action) {
315         case SCST_PROC_ACTION_ALL:
316                 level = TRACE_ALL;
317                 break;
318         case SCST_PROC_ACTION_DEFAULT:
319                 level = default_level;
320                 break;
321         case SCST_PROC_ACTION_NONE:
322                 level = TRACE_NULL;
323                 break;
324         case SCST_PROC_ACTION_SET:
325         case SCST_PROC_ACTION_ADD:
326         case SCST_PROC_ACTION_DEL:
327                 while (isspace(*p) && *p != '\0')
328                         p++;
329                 e = p;
330                 while (!isspace(*e) && *e != '\0')
331                         e++;
332                 *e = 0;
333                 if (tbl) {
334                         t = tbl;
335                         while (t->token) {
336                                 if (!strcasecmp(p, t->token)) {
337                                         level = t->val;
338                                         break;
339                                 }
340                                 t++;
341                         }
342                 }
343                 if (level == 0) {
344                         t = scst_proc_trace_tbl;
345                         while (t->token) {
346                                 if (!strcasecmp(p, t->token)) {
347                                         level = t->val;
348                                         break;
349                                 }
350                                 t++;
351                         }
352                 }
353                 if (level == 0) {
354                         PRINT_ERROR("Unknown token \"%s\"", p);
355                         res = -EINVAL;
356                         goto out_free;
357                 }
358                 break;
359         case SCST_PROC_ACTION_VALUE:
360                 while (isspace(*p) && *p != '\0')
361                         p++;
362                 level = simple_strtoul(p, NULL, 0);
363                 break;
364         }
365
366         oldlevel = *log_level;
367
368         switch (action) {
369         case SCST_PROC_ACTION_ADD:
370                 *log_level |= level;
371                 break;
372         case SCST_PROC_ACTION_DEL:
373                 *log_level &= ~level;
374                 break;
375         default:
376                 *log_level = level;
377                 break;
378         }
379
380         PRINT_INFO("Changed trace level for \"%s\": "
381                    "old 0x%08lx, new 0x%08lx",
382                    (char *)data, oldlevel, *log_level);
383
384 out_free:
385         free_page((unsigned long)buffer);
386 out:
387         TRACE_EXIT_RES(res);
388         return res;
389 }
390 EXPORT_SYMBOL(scst_proc_log_entry_write);
391
392 static ssize_t scst_proc_scsi_tgt_gen_write_log(struct file *file,
393                                         const char __user *buf,
394                                         size_t length, loff_t *off)
395 {
396         int res;
397
398         TRACE_ENTRY();
399
400         if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
401                 res = -EINTR;
402                 goto out;
403         }
404
405         res = scst_proc_log_entry_write(file, buf, length,
406                 &trace_flag, SCST_DEFAULT_LOG_FLAGS,
407                 scst_proc_local_trace_tbl);
408
409         mutex_unlock(&scst_log_mutex);
410
411 out:
412         TRACE_EXIT_RES(res);
413         return res;
414 }
415
416 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
417
418 #ifdef CONFIG_SCST_MEASURE_LATENCY
419
420 static int lat_info_show(struct seq_file *seq, void *v)
421 {
422         int res = 0;
423         struct scst_acg *acg;
424         struct scst_session *sess;
425
426         TRACE_ENTRY();
427
428         if (mutex_lock_interruptible(&scst_mutex) != 0) {
429                 res = -EINTR;
430                 goto out;
431         }
432
433         seq_printf(seq, "%-20s %-45s %-15s %15s\n",
434                    "Target name",
435                    "Initiator name",
436                    "SCST latency",
437                    "Processing latency (ns)");
438
439         list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
440                 list_for_each_entry(sess, &acg->acg_sess_list,
441                                 acg_sess_list_entry) {
442                         unsigned long proc_lat = 0, scst_lat = 0;
443                         uint64_t proc_time, scst_time;
444                         unsigned int processed_cmds;
445
446                         spin_lock_bh(&sess->meas_lock);
447                         proc_time = sess->processing_time;
448                         scst_time = sess->scst_time;
449                         processed_cmds = sess->processed_cmds;
450                         spin_unlock_bh(&sess->meas_lock);
451
452                         TRACE_DBG("sess %p, scst_time %lld, proc_time %lld, "
453                                 "processed_cmds %d", sess, scst_time,
454                                 proc_time, processed_cmds);
455
456 #if BITS_PER_LONG == 32
457                         /* Unfortunately, do_div() doesn't work too well */
458                         while (((proc_time & 0xFFFFFFFF00000000LL) != 0) ||
459                                ((scst_time & 0xFFFFFFFF00000000LL) != 0)) {
460                                 TRACE_DBG("%s", "Gathered time too big");
461                                 proc_time >>= 1;
462                                 scst_time >>= 1;
463                                 processed_cmds >>= 1;
464                         }
465 #endif
466
467                         if (sess->processed_cmds != 0) {
468                                 proc_lat = (unsigned long)proc_time /
469                                                 processed_cmds;
470                                 scst_lat = (unsigned long)scst_time /
471                                                 processed_cmds;
472                         }
473
474                         seq_printf(seq, "%-20s %-45s %-15ld %-15ld\n",
475                                         sess->tgt->tgtt->name,
476                                         sess->initiator_name,
477                                         scst_lat, proc_lat);
478                 }
479         }
480
481         mutex_unlock(&scst_mutex);
482
483 out:
484         TRACE_EXIT_RES(res);
485         return res;
486 }
487
488 static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file,
489                                         const char __user *buf,
490                                         size_t length, loff_t *off)
491 {
492         int res = length;
493         struct scst_acg *acg;
494         struct scst_session *sess;
495
496         TRACE_ENTRY();
497
498         if (mutex_lock_interruptible(&scst_mutex) != 0) {
499                 res = -EINTR;
500                 goto out;
501         }
502
503         list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
504                 list_for_each_entry(sess, &acg->acg_sess_list,
505                                 acg_sess_list_entry) {
506                         PRINT_INFO("Zeroing latency statistics for initiator"
507                                 " %s",
508                                 sess->initiator_name);
509                         spin_lock_bh(&sess->meas_lock);
510                         sess->processing_time = 0;
511                         sess->scst_time = 0;
512                         sess->processed_cmds = 0;
513                         spin_unlock_bh(&sess->meas_lock);
514                 }
515         }
516
517         mutex_unlock(&scst_mutex);
518
519 out:
520         TRACE_EXIT_RES(res);
521         return res;
522 }
523
524 static struct scst_proc_data scst_lat_proc_data = {
525         SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_lat)
526         .show = lat_info_show,
527         .data = "scsi_tgt",
528 };
529
530 #endif /* CONFIG_SCST_MEASURE_LATENCY */
531
532 static int __init scst_proc_init_module_log(void)
533 {
534         int res = 0;
535 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) || \
536     defined(CONFIG_SCST_MEASURE_LATENCY)
537         struct proc_dir_entry *generic;
538 #endif
539
540         TRACE_ENTRY();
541
542 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
543         generic = scst_create_proc_entry(scst_proc_scsi_tgt,
544                                          SCST_PROC_LOG_ENTRY_NAME,
545                                          &scst_log_proc_data);
546         if (!generic) {
547                 PRINT_ERROR("cannot init /proc/%s/%s",
548                             SCST_PROC_ENTRY_NAME, SCST_PROC_LOG_ENTRY_NAME);
549                 res = -ENOMEM;
550         }
551 #endif
552
553 #ifdef CONFIG_SCST_MEASURE_LATENCY
554         if (res == 0) {
555                 generic = scst_create_proc_entry(scst_proc_scsi_tgt,
556                                          SCST_PROC_LAT_ENTRY_NAME,
557                                          &scst_lat_proc_data);
558                 if (!generic) {
559                         PRINT_ERROR("cannot init /proc/%s/%s",
560                                     SCST_PROC_ENTRY_NAME,
561                                     SCST_PROC_LAT_ENTRY_NAME);
562                         res = -ENOMEM;
563                 }
564         }
565 #endif
566
567         TRACE_EXIT_RES(res);
568         return res;
569 }
570
571 static void scst_proc_cleanup_module_log(void)
572 {
573         TRACE_ENTRY();
574
575 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
576         remove_proc_entry(SCST_PROC_LOG_ENTRY_NAME, scst_proc_scsi_tgt);
577 #endif
578
579 #ifdef CONFIG_SCST_MEASURE_LATENCY
580         remove_proc_entry(SCST_PROC_LAT_ENTRY_NAME, scst_proc_scsi_tgt);
581 #endif
582
583         TRACE_EXIT();
584         return;
585 }
586
587 static int scst_proc_group_add_tree(struct scst_acg *acg, const char *name)
588 {
589         int res = 0;
590         struct proc_dir_entry *generic;
591
592         TRACE_ENTRY();
593
594         acg->acg_proc_root = proc_mkdir(name, scst_proc_groups_root);
595         if (acg->acg_proc_root == NULL) {
596                 PRINT_ERROR("Not enough memory to register %s entry in "
597                                "/proc/%s/%s", name, SCST_PROC_ENTRY_NAME,
598                                SCST_PROC_GROUPS_ENTRY_NAME);
599                 goto out;
600         }
601
602         scst_groups_devices_proc_data.data = acg;
603         generic = scst_create_proc_entry(acg->acg_proc_root,
604                                          SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
605                                          &scst_groups_devices_proc_data);
606         if (!generic) {
607                 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
608                                SCST_PROC_ENTRY_NAME,
609                                SCST_PROC_GROUPS_ENTRY_NAME,
610                                name, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME);
611                 res = -ENOMEM;
612                 goto out_remove;
613         }
614
615         scst_groups_names_proc_data.data = acg;
616         generic = scst_create_proc_entry(acg->acg_proc_root,
617                                          SCST_PROC_GROUPS_USERS_ENTRY_NAME,
618                                          &scst_groups_names_proc_data);
619         if (!generic) {
620                 PRINT_ERROR("cannot init /proc/%s/%s/%s/%s",
621                                SCST_PROC_ENTRY_NAME,
622                                SCST_PROC_GROUPS_ENTRY_NAME,
623                                name, SCST_PROC_GROUPS_USERS_ENTRY_NAME);
624                 res = -ENOMEM;
625                 goto out_remove1;
626         }
627
628 out:
629         TRACE_EXIT_RES(res);
630         return res;
631
632 out_remove1:
633         remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
634                           acg->acg_proc_root);
635
636 out_remove:
637         remove_proc_entry(name, scst_proc_groups_root);
638         goto out;
639 }
640
641 static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
642         const char *name)
643 {
644         TRACE_ENTRY();
645
646         remove_proc_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME, acg_proc_root);
647         remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
648                                 acg_proc_root);
649         remove_proc_entry(name, scst_proc_groups_root);
650
651         TRACE_EXIT();
652         return;
653 }
654
655 /* The activity supposed to be suspended and scst_mutex held */
656 static int scst_proc_group_add(const char *p)
657 {
658         int res = 0, len = strlen(p) + 1;
659         struct scst_acg *acg;
660         char *name = NULL;
661
662         TRACE_ENTRY();
663
664         name = kmalloc(len, GFP_KERNEL);
665         if (name == NULL) {
666                 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of name failed");
667                 goto out_nomem;
668         }
669         strncpy(name, p, len);
670
671         acg = scst_alloc_add_acg(name);
672         if (acg == NULL) {
673                 PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", name);
674                 goto out_free;
675         }
676
677         res = scst_proc_group_add_tree(acg, p);
678         if (res != 0)
679                 goto out_free_acg;
680
681 out:
682         TRACE_EXIT_RES(res);
683         return res;
684
685 out_free_acg:
686         scst_proc_del_free_acg(acg, 0);
687
688 out_free:
689         kfree(name);
690
691 out_nomem:
692         res = -ENOMEM;
693         goto out;
694 }
695
696 /* The activity supposed to be suspended and scst_mutex held */
697 static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc)
698 {
699         const char *name;
700         struct proc_dir_entry *acg_proc_root = acg->acg_proc_root;
701         int res = 0;
702
703         TRACE_ENTRY();
704
705         if (acg != scst_default_acg) {
706                 name = acg->acg_name;
707                 res = scst_destroy_acg(acg);
708                 if (res == 0) {
709                         if (remove_proc)
710                                 scst_proc_del_acg_tree(acg_proc_root, name);
711                         kfree(name);
712                 }
713         }
714
715         TRACE_EXIT_RES(res);
716         return res;
717 }
718
719 /* The activity supposed to be suspended and scst_mutex held */
720 static int scst_proc_rename_acg(struct scst_acg *acg, const char *new_name)
721 {
722         int res = 0, len = strlen(new_name) + 1;
723         char *name;
724         struct proc_dir_entry *old_acg_proc_root = acg->acg_proc_root;
725
726         TRACE_ENTRY();
727
728         name = kmalloc(len, GFP_KERNEL);
729         if (name == NULL) {
730                 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of new name failed");
731                 goto out_nomem;
732         }
733         strncpy(name, new_name, len);
734
735         res = scst_proc_group_add_tree(acg, new_name);
736         if (res != 0)
737                 goto out_free;
738
739         scst_proc_del_acg_tree(old_acg_proc_root, acg->acg_name);
740
741         kfree(acg->acg_name);
742         acg->acg_name = name;
743
744         scst_check_reassign_sessions();
745
746 out:
747         TRACE_EXIT_RES(res);
748         return res;
749
750 out_free:
751         kfree(name);
752
753 out_nomem:
754         res = -ENOMEM;
755         goto out;
756 }
757
758 static int __init scst_proc_init_groups(void)
759 {
760         int res = 0;
761
762         TRACE_ENTRY();
763
764         /* create the proc directory entry for the device */
765         scst_proc_groups_root = proc_mkdir(SCST_PROC_GROUPS_ENTRY_NAME,
766                                            scst_proc_scsi_tgt);
767         if (scst_proc_groups_root == NULL) {
768                 PRINT_ERROR("Not enough memory to register %s entry in "
769                                "/proc/%s", SCST_PROC_GROUPS_ENTRY_NAME,
770                                SCST_PROC_ENTRY_NAME);
771                 goto out_nomem;
772         }
773
774         res = scst_proc_group_add_tree(scst_default_acg,
775                                         SCST_DEFAULT_ACG_NAME);
776         if (res != 0)
777                 goto out_remove;
778
779 out:
780         TRACE_EXIT_RES(res);
781         return res;
782
783 out_remove:
784         remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
785
786 out_nomem:
787         res = -ENOMEM;
788         goto out;
789 }
790
791 static void scst_proc_cleanup_groups(void)
792 {
793         struct scst_acg *acg_tmp, *acg;
794
795         TRACE_ENTRY();
796
797         /* remove all groups (dir & entries) */
798         list_for_each_entry_safe(acg, acg_tmp, &scst_acg_list,
799                                  scst_acg_list_entry) {
800                 scst_proc_del_free_acg(acg, 1);
801         }
802
803         scst_proc_del_acg_tree(scst_default_acg->acg_proc_root,
804                                 SCST_DEFAULT_ACG_NAME);
805         TRACE_DBG("remove_proc_entry(%s, %p)",
806                   SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
807         remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
808
809         TRACE_EXIT();
810 }
811
812 static int __init scst_proc_init_sgv(void)
813 {
814         int res = 0;
815         struct proc_dir_entry *pr;
816
817         TRACE_ENTRY();
818
819         pr = scst_create_proc_entry(scst_proc_scsi_tgt, "sgv",
820                                 &scst_sgv_proc_data);
821         if (pr == NULL) {
822                 PRINT_ERROR("%s", "cannot create sgv /proc entry");
823                 res = -ENOMEM;
824         }
825
826         TRACE_EXIT_RES(res);
827         return res;
828 }
829
830 static void __exit scst_proc_cleanup_sgv(void)
831 {
832         TRACE_ENTRY();
833         remove_proc_entry("sgv", scst_proc_scsi_tgt);
834         TRACE_EXIT();
835 }
836
837 int __init scst_proc_init_module(void)
838 {
839         int res = 0;
840         struct proc_dir_entry *generic;
841
842         TRACE_ENTRY();
843
844         scst_proc_scsi_tgt = proc_mkdir(SCST_PROC_ENTRY_NAME, NULL);
845         if (!scst_proc_scsi_tgt) {
846                 PRINT_ERROR("cannot init /proc/%s", SCST_PROC_ENTRY_NAME);
847                 goto out_nomem;
848         }
849
850         generic = scst_create_proc_entry(scst_proc_scsi_tgt,
851                                          SCST_PROC_ENTRY_NAME,
852                                          &scst_tgt_proc_data);
853         if (!generic) {
854                 PRINT_ERROR("cannot init /proc/%s/%s",
855                             SCST_PROC_ENTRY_NAME, SCST_PROC_ENTRY_NAME);
856                 goto out_remove;
857         }
858
859         generic = scst_create_proc_entry(scst_proc_scsi_tgt,
860                                          SCST_PROC_VERSION_NAME,
861                                          &scst_version_proc_data);
862         if (!generic) {
863                 PRINT_ERROR("cannot init /proc/%s/%s",
864                             SCST_PROC_ENTRY_NAME, SCST_PROC_VERSION_NAME);
865                 goto out_remove1;
866         }
867
868         generic = scst_create_proc_entry(scst_proc_scsi_tgt,
869                                          SCST_PROC_SESSIONS_NAME,
870                                          &scst_sessions_proc_data);
871         if (!generic) {
872                 PRINT_ERROR("cannot init /proc/%s/%s",
873                             SCST_PROC_ENTRY_NAME, SCST_PROC_SESSIONS_NAME);
874                 goto out_remove2;
875         }
876
877         generic = scst_create_proc_entry(scst_proc_scsi_tgt,
878                                          SCST_PROC_HELP_NAME,
879                                          &scst_help_proc_data);
880         if (!generic) {
881                 PRINT_ERROR("cannot init /proc/%s/%s",
882                             SCST_PROC_ENTRY_NAME, SCST_PROC_HELP_NAME);
883                 goto out_remove3;
884         }
885
886         generic = scst_create_proc_entry(scst_proc_scsi_tgt,
887                                          SCST_PROC_THREADS_NAME,
888                                          &scst_threads_proc_data);
889         if (!generic) {
890                 PRINT_ERROR("cannot init /proc/%s/%s",
891                             SCST_PROC_ENTRY_NAME, SCST_PROC_THREADS_NAME);
892                 goto out_remove4;
893         }
894
895         if (scst_proc_init_module_log() < 0)
896                 goto out_remove5;
897
898         if (scst_proc_init_groups() < 0)
899                 goto out_remove6;
900
901         if (scst_proc_init_sgv() < 0)
902                 goto out_remove7;
903
904 out:
905         TRACE_EXIT_RES(res);
906         return res;
907
908 out_remove7:
909         scst_proc_cleanup_groups();
910
911 out_remove6:
912         scst_proc_cleanup_module_log();
913
914 out_remove5:
915         remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
916
917 out_remove4:
918         remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
919
920 out_remove3:
921         remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
922
923 out_remove2:
924         remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
925
926 out_remove1:
927         remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
928
929 out_remove:
930         remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
931
932 out_nomem:
933         res = -ENOMEM;
934         goto out;
935 }
936
937 void __exit scst_proc_cleanup_module(void)
938 {
939         TRACE_ENTRY();
940
941         /* We may not bother about locks here */
942         scst_proc_cleanup_sgv();
943         scst_proc_cleanup_groups();
944         scst_proc_cleanup_module_log();
945         remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
946         remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
947         remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
948         remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
949         remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
950         remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL);
951
952         TRACE_EXIT();
953 }
954
955 static ssize_t scst_proc_threads_write(struct file *file,
956                                        const char __user *buf,
957                                        size_t length, loff_t *off)
958 {
959         int res = length;
960         int oldtn, newtn, delta;
961         char *buffer;
962
963         TRACE_ENTRY();
964
965         if (length > SCST_PROC_BLOCK_SIZE) {
966                 res = -EOVERFLOW;
967                 goto out;
968         }
969         if (!buf) {
970                 res = -EINVAL;
971                 goto out;
972         }
973         buffer = (char *)__get_free_page(GFP_KERNEL);
974         if (!buffer) {
975                 res = -ENOMEM;
976                 goto out;
977         }
978         if (copy_from_user(buffer, buf, length)) {
979                 res = -EFAULT;
980                 goto out_free;
981         }
982         if (length < PAGE_SIZE) {
983                 buffer[length] = '\0';
984         } else if (buffer[PAGE_SIZE-1]) {
985                 res = -EINVAL;
986                 goto out_free;
987         }
988
989         if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
990                 res = -EINTR;
991                 goto out_free;
992         }
993
994         mutex_lock(&scst_global_threads_mutex);
995
996         oldtn = scst_nr_global_threads;
997         newtn = simple_strtoul(buffer, NULL, 0);
998         if (newtn <= 0) {
999                 PRINT_ERROR("Illegal threads num value %d", newtn);
1000                 res = -EINVAL;
1001                 goto out_up_thr_free;
1002         }
1003         delta = newtn - oldtn;
1004         if (delta < 0)
1005                 __scst_del_global_threads(-delta);
1006         else
1007                 __scst_add_global_threads(delta);
1008
1009         PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
1010
1011 out_up_thr_free:
1012         mutex_unlock(&scst_global_threads_mutex);
1013
1014         mutex_unlock(&scst_proc_mutex);
1015
1016 out_free:
1017         free_page((unsigned long)buffer);
1018 out:
1019         TRACE_EXIT_RES(res);
1020         return res;
1021 }
1022
1023 int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt)
1024 {
1025         int res = 0;
1026
1027         TRACE_ENTRY();
1028
1029         /* create the proc directory entry for the device */
1030         vtt->proc_tgt_root = proc_mkdir(vtt->name, scst_proc_scsi_tgt);
1031         if (vtt->proc_tgt_root == NULL) {
1032                 PRINT_ERROR("Not enough memory to register SCSI target %s "
1033                     "in /proc/%s", vtt->name, SCST_PROC_ENTRY_NAME);
1034                 goto out_nomem;
1035         }
1036
1037 out:
1038         TRACE_EXIT_RES(res);
1039         return res;
1040
1041 out_nomem:
1042         res = -ENOMEM;
1043         goto out;
1044 }
1045
1046 void scst_cleanup_proc_target_dir_entries(struct scst_tgt_template *vtt)
1047 {
1048         TRACE_ENTRY();
1049
1050         remove_proc_entry(vtt->name, scst_proc_scsi_tgt);
1051
1052         TRACE_EXIT();
1053         return;
1054 }
1055
1056 /* Called under scst_mutex */
1057 int scst_build_proc_target_entries(struct scst_tgt *vtt)
1058 {
1059         int res = 0;
1060         struct proc_dir_entry *p;
1061         char name[20];
1062
1063         TRACE_ENTRY();
1064
1065         if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1066                 /* create the proc file entry for the device */
1067                 scnprintf(name, sizeof(name), "%d", vtt->tgtt->proc_dev_num);
1068                 scst_scsi_tgt_proc_data.data = (void *)vtt;
1069                 p = scst_create_proc_entry(vtt->tgtt->proc_tgt_root,
1070                                            name,
1071                                            &scst_scsi_tgt_proc_data);
1072                 if (p == NULL) {
1073                         PRINT_ERROR("Not enough memory to register SCSI "
1074                              "target entry %s in /proc/%s/%s", name,
1075                              SCST_PROC_ENTRY_NAME, vtt->tgtt->name);
1076                         res = -ENOMEM;
1077                         goto out;
1078                 }
1079                 vtt->proc_num = vtt->tgtt->proc_dev_num;
1080                 vtt->tgtt->proc_dev_num++;
1081         }
1082
1083 out:
1084         TRACE_EXIT_RES(res);
1085         return res;
1086 }
1087
1088 void scst_cleanup_proc_target_entries(struct scst_tgt *vtt)
1089 {
1090         char name[20];
1091
1092         TRACE_ENTRY();
1093
1094         if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) {
1095                 scnprintf(name, sizeof(name), "%d", vtt->proc_num);
1096                 remove_proc_entry(name, vtt->tgtt->proc_tgt_root);
1097         }
1098
1099         TRACE_EXIT();
1100         return;
1101 }
1102
1103 static ssize_t scst_proc_scsi_tgt_write(struct file *file,
1104                                         const char __user *buf,
1105                                         size_t length, loff_t *off)
1106 {
1107         struct scst_tgt *vtt =
1108                 (struct scst_tgt *)PDE(file->f_dentry->d_inode)->data;
1109         ssize_t res = 0;
1110         char *buffer;
1111         char *start;
1112         int eof = 0;
1113
1114         TRACE_ENTRY();
1115
1116         if (vtt->tgtt->write_proc == NULL) {
1117                 res = -ENOSYS;
1118                 goto out;
1119         }
1120
1121         if (length > SCST_PROC_BLOCK_SIZE) {
1122                 res = -EOVERFLOW;
1123                 goto out;
1124         }
1125         if (!buf) {
1126                 res = -EINVAL;
1127                 goto out;
1128         }
1129         buffer = (char *)__get_free_page(GFP_KERNEL);
1130         if (!buffer) {
1131                 res = -ENOMEM;
1132                 goto out;
1133         }
1134         if (copy_from_user(buffer, buf, length)) {
1135                 res = -EFAULT;
1136                 goto out_free;
1137         }
1138         if (length < PAGE_SIZE) {
1139                 buffer[length] = '\0';
1140         } else if (buffer[PAGE_SIZE-1]) {
1141                 res = -EINVAL;
1142                 goto out_free;
1143         }
1144
1145         TRACE_BUFFER("Buffer", buffer, length);
1146
1147         if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1148                 res = -EINTR;
1149                 goto out_free;
1150         }
1151
1152         res = vtt->tgtt->write_proc(buffer, &start, 0, length, &eof, vtt);
1153
1154         mutex_unlock(&scst_proc_mutex);
1155
1156 out_free:
1157         free_page((unsigned long)buffer);
1158 out:
1159         TRACE_EXIT_RES(res);
1160         return res;
1161 }
1162
1163 int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1164 {
1165         int res = 0;
1166         struct proc_dir_entry *p;
1167
1168         TRACE_ENTRY();
1169
1170         sBUG_ON(dev_type->proc_dev_type_root);
1171
1172         /* create the proc directory entry for the dev type handler */
1173         dev_type->proc_dev_type_root = proc_mkdir(dev_type->name,
1174                                                   scst_proc_scsi_tgt);
1175         if (dev_type->proc_dev_type_root == NULL) {
1176                 PRINT_ERROR("Not enough memory to register dev handler dir "
1177                     "%s in /proc/%s", dev_type->name, SCST_PROC_ENTRY_NAME);
1178                 goto out_nomem;
1179         }
1180
1181         scst_dev_handler_type_proc_data.data = dev_type;
1182         if (dev_type->type >= 0) {
1183                 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1184                                    SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1185                                    &scst_dev_handler_type_proc_data);
1186                 if (p == NULL) {
1187                         PRINT_ERROR("Not enough memory to register dev "
1188                              "handler entry %s in /proc/%s/%s",
1189                              SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1190                              SCST_PROC_ENTRY_NAME, dev_type->name);
1191                         goto out_remove;
1192                 }
1193         }
1194
1195         if (dev_type->read_proc || dev_type->write_proc) {
1196                 /* create the proc file entry for the dev type handler */
1197                 scst_dev_handler_proc_data.data = (void *)dev_type;
1198                 p = scst_create_proc_entry(dev_type->proc_dev_type_root,
1199                                            dev_type->name,
1200                                            &scst_dev_handler_proc_data);
1201                 if (p == NULL) {
1202                         PRINT_ERROR("Not enough memory to register dev "
1203                              "handler entry %s in /proc/%s/%s", dev_type->name,
1204                              SCST_PROC_ENTRY_NAME, dev_type->name);
1205                         goto out_remove1;
1206                 }
1207         }
1208
1209 out:
1210         TRACE_EXIT_RES(res);
1211         return res;
1212
1213 out_remove1:
1214         if (dev_type->type >= 0)
1215                 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1216                                   dev_type->proc_dev_type_root);
1217
1218 out_remove:
1219         remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1220
1221 out_nomem:
1222         res = -ENOMEM;
1223         goto out;
1224 }
1225
1226 void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1227 {
1228         TRACE_ENTRY();
1229
1230         sBUG_ON(dev_type->proc_dev_type_root == NULL);
1231
1232         if (dev_type->type >= 0) {
1233                 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1234                                   dev_type->proc_dev_type_root);
1235         }
1236         if (dev_type->read_proc || dev_type->write_proc)
1237                 remove_proc_entry(dev_type->name, dev_type->proc_dev_type_root);
1238         remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1239         dev_type->proc_dev_type_root = NULL;
1240
1241         TRACE_EXIT();
1242         return;
1243 }
1244
1245 static ssize_t scst_proc_scsi_dev_handler_write(struct file *file,
1246                                                 const char __user *buf,
1247                                                 size_t length, loff_t *off)
1248 {
1249         struct scst_dev_type *dev_type =
1250                 (struct scst_dev_type *)PDE(file->f_dentry->d_inode)->data;
1251         ssize_t res = 0;
1252         char *buffer;
1253         char *start;
1254         int eof = 0;
1255
1256         TRACE_ENTRY();
1257
1258         if (dev_type->write_proc == NULL) {
1259                 res = -ENOSYS;
1260                 goto out;
1261         }
1262
1263         if (length > SCST_PROC_BLOCK_SIZE) {
1264                 res = -EOVERFLOW;
1265                 goto out;
1266         }
1267         if (!buf) {
1268                 res = -EINVAL;
1269                 goto out;
1270         }
1271
1272         buffer = (char *)__get_free_page(GFP_KERNEL);
1273         if (!buffer) {
1274                 res = -ENOMEM;
1275                 goto out;
1276         }
1277
1278         if (copy_from_user(buffer, buf, length)) {
1279                 res = -EFAULT;
1280                 goto out_free;
1281         }
1282         if (length < PAGE_SIZE) {
1283                 buffer[length] = '\0';
1284         } else if (buffer[PAGE_SIZE-1]) {
1285                 res = -EINVAL;
1286                 goto out_free;
1287         }
1288
1289         TRACE_BUFFER("Buffer", buffer, length);
1290
1291         if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
1292                 res = -EINTR;
1293                 goto out_free;
1294         }
1295
1296         res = dev_type->write_proc(buffer, &start, 0, length, &eof, dev_type);
1297
1298         mutex_unlock(&scst_proc_mutex);
1299
1300 out_free:
1301         free_page((unsigned long)buffer);
1302
1303 out:
1304         TRACE_EXIT_RES(res);
1305         return res;
1306 }
1307
1308 static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file,
1309                                         const char __user *buf,
1310                                         size_t length, loff_t *off)
1311 {
1312         int res, rc = 0, action;
1313         char *buffer, *p, *pp;
1314         struct scst_acg *a, *acg = NULL;
1315
1316         TRACE_ENTRY();
1317
1318         if (length > SCST_PROC_BLOCK_SIZE) {
1319                 res = -EOVERFLOW;
1320                 goto out;
1321         }
1322         if (!buf) {
1323                 res = -EINVAL;
1324                 goto out;
1325         }
1326         buffer = (char *)__get_free_page(GFP_KERNEL);
1327         if (!buffer) {
1328                 res = -ENOMEM;
1329                 goto out;
1330         }
1331         if (copy_from_user(buffer, buf, length)) {
1332                 res = -EFAULT;
1333                 goto out_free;
1334         }
1335         if (length < PAGE_SIZE) {
1336                 buffer[length] = '\0';
1337         } else if (buffer[PAGE_SIZE-1]) {
1338                 res = -EINVAL;
1339                 goto out_free;
1340         }
1341
1342         /*
1343          * Usage: echo "add_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1344          *   or   echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt
1345          *   or   echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt"
1346          *   or   echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt
1347          */
1348         p = buffer;
1349         if (p[strlen(p) - 1] == '\n')
1350                 p[strlen(p) - 1] = '\0';
1351         if (!strncasecmp("assign ", p, 7)) {
1352                 p += 7;
1353                 action = SCST_PROC_ACTION_ASSIGN;
1354         } else if (!strncasecmp("add_group ", p, 10)) {
1355                 p += 10;
1356                 action = SCST_PROC_ACTION_ADD_GROUP;
1357         } else if (!strncasecmp("del_group ", p, 10)) {
1358                 p += 10;
1359                 action = SCST_PROC_ACTION_DEL_GROUP;
1360         } else if (!strncasecmp("rename_group ", p, 13)) {
1361                 p += 13;
1362                 action = SCST_PROC_ACTION_RENAME_GROUP;
1363         } else {
1364                 PRINT_ERROR("Unknown action \"%s\"", p);
1365                 res = -EINVAL;
1366                 goto out_free;
1367         }
1368
1369         res = scst_suspend_activity(true);
1370         if (res != 0)
1371                 goto out_free;
1372
1373         if (mutex_lock_interruptible(&scst_mutex) != 0) {
1374                 res = -EINTR;
1375                 goto out_free_resume;
1376         }
1377
1378         res = length;
1379
1380         switch (action) {
1381         case SCST_PROC_ACTION_ADD_GROUP:
1382         case SCST_PROC_ACTION_DEL_GROUP:
1383         case SCST_PROC_ACTION_RENAME_GROUP:
1384                 pp = p;
1385                 while (!isspace(*pp) && *pp != '\0')
1386                         pp++;
1387                 if (*pp != '\0') {
1388                         *pp = '\0';
1389                         pp++;
1390                         while (isspace(*pp) && *pp != '\0')
1391                                 pp++;
1392                         if (*pp != '\0') {
1393                                 switch (action) {
1394                                 case SCST_PROC_ACTION_ADD_GROUP:
1395                                 case SCST_PROC_ACTION_DEL_GROUP:
1396                                         PRINT_ERROR("%s", "Too many "
1397                                                 "arguments");
1398                                         res = -EINVAL;
1399                                         goto out_up_free;
1400                                 }
1401                         }
1402                 }
1403
1404                 if (strcmp(p, SCST_DEFAULT_ACG_NAME) == 0) {
1405                         PRINT_ERROR("Attempt to add/delete/rename predefined "
1406                                 "group \"%s\"", p);
1407                         res = -EINVAL;
1408                         goto out_up_free;
1409                 }
1410
1411                 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1412                         if (strcmp(a->acg_name, p) == 0) {
1413                                 TRACE_DBG("group (acg) %p %s found",
1414                                           a, a->acg_name);
1415                                 acg = a;
1416                                 break;
1417                         }
1418                 }
1419
1420                 switch (action) {
1421                 case SCST_PROC_ACTION_ADD_GROUP:
1422                         if (acg) {
1423                                 PRINT_ERROR("acg name %s exist", p);
1424                                 res = -EINVAL;
1425                                 goto out_up_free;
1426                         }
1427                         rc = scst_proc_group_add(p);
1428                         break;
1429                 case SCST_PROC_ACTION_DEL_GROUP:
1430                         if (acg == NULL) {
1431                                 PRINT_ERROR("acg name %s not found", p);
1432                                 res = -EINVAL;
1433                                 goto out_up_free;
1434                         }
1435                         rc = scst_proc_del_free_acg(acg, 1);
1436                         break;
1437                 case SCST_PROC_ACTION_RENAME_GROUP:
1438                         if (acg == NULL) {
1439                                 PRINT_ERROR("acg name %s not found", p);
1440                                 res = -EINVAL;
1441                                 goto out_up_free;
1442                         }
1443
1444                         p = pp;
1445                         while (!isspace(*pp) && *pp != '\0')
1446                                 pp++;
1447                         if (*pp != '\0') {
1448                                 *pp = '\0';
1449                                 pp++;
1450                                 while (isspace(*pp) && *pp != '\0')
1451                                         pp++;
1452                                 if (*pp != '\0') {
1453                                         PRINT_ERROR("%s", "Too many arguments");
1454                                         res = -EINVAL;
1455                                         goto out_up_free;
1456                                 }
1457                         }
1458                         rc = scst_proc_rename_acg(acg, p);
1459                         break;
1460                 }
1461                 break;
1462         case SCST_PROC_ACTION_ASSIGN:
1463                 rc = scst_proc_assign_handler(p);
1464                 break;
1465         }
1466
1467         if (rc != 0)
1468                 res = rc;
1469
1470 out_up_free:
1471         mutex_unlock(&scst_mutex);
1472
1473 out_free_resume:
1474         scst_resume_activity();
1475
1476 out_free:
1477         free_page((unsigned long)buffer);
1478
1479 out:
1480         TRACE_EXIT_RES(res);
1481         return res;
1482 }
1483
1484 /* The activity supposed to be suspended and scst_mutex held */
1485 static int scst_proc_assign_handler(char *buf)
1486 {
1487         int res = 0;
1488         char *p = buf, *e, *ee;
1489         unsigned long host, channel = 0, id = 0, lun = 0;
1490         struct scst_device *d, *dev = NULL;
1491         struct scst_dev_type *dt, *handler = NULL;
1492
1493         TRACE_ENTRY();
1494
1495         while (isspace(*p) && *p != '\0')
1496                 p++;
1497
1498         host = simple_strtoul(p, &p, 0);
1499         if ((host == ULONG_MAX) || (*p != ':'))
1500                 goto out_synt_err;
1501         p++;
1502         channel = simple_strtoul(p, &p, 0);
1503         if ((channel == ULONG_MAX) || (*p != ':'))
1504                 goto out_synt_err;
1505         p++;
1506         id = simple_strtoul(p, &p, 0);
1507         if ((channel == ULONG_MAX) || (*p != ':'))
1508                 goto out_synt_err;
1509         p++;
1510         lun = simple_strtoul(p, &p, 0);
1511         if (lun == ULONG_MAX)
1512                 goto out_synt_err;
1513
1514         e = p;
1515         e++;
1516         while (isspace(*e) && *e != '\0')
1517                 e++;
1518         ee = e;
1519         while (!isspace(*ee) && *ee != '\0')
1520                 ee++;
1521         *ee = '\0';
1522
1523         TRACE_DBG("Dev %ld:%ld:%ld:%ld, handler %s", host, channel, id, lun, e);
1524
1525         list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1526                 if ((d->virt_id == 0) &&
1527                     d->scsi_dev->host->host_no == host &&
1528                     d->scsi_dev->channel == channel &&
1529                     d->scsi_dev->id == id &&
1530                     d->scsi_dev->lun == lun) {
1531                         dev = d;
1532                         TRACE_DBG("Dev %p (%ld:%ld:%ld:%ld) found",
1533                                   dev, host, channel, id, lun);
1534                         break;
1535                 }
1536         }
1537
1538         if (dev == NULL) {
1539                 PRINT_ERROR("Device %ld:%ld:%ld:%ld not found",
1540                                host, channel, id, lun);
1541                 res = -EINVAL;
1542                 goto out;
1543         }
1544
1545         list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
1546                 if (!strcmp(dt->name, e)) {
1547                         handler = dt;
1548                         TRACE_DBG("Dev handler %p with name %s found",
1549                                   dt, dt->name);
1550                         break;
1551                 }
1552         }
1553
1554         if (handler == NULL) {
1555                 PRINT_ERROR("Handler %s not found", e);
1556                 res = -EINVAL;
1557                 goto out;
1558         }
1559
1560         if (dev->scsi_dev->type != handler->type) {
1561                 PRINT_ERROR("Type %d of device %s differs from type "
1562                         "%d of dev handler %s", dev->type,
1563                         dev->handler->name, handler->type, handler->name);
1564                 res = -EINVAL;
1565                 goto out;
1566         }
1567
1568         res = scst_assign_dev_handler(dev, handler);
1569
1570 out:
1571         TRACE_EXIT_RES(res);
1572         return res;
1573
1574 out_synt_err:
1575         PRINT_ERROR("Syntax error on %s", p);
1576         res = -EINVAL;
1577         goto out;
1578 }
1579
1580 static ssize_t scst_proc_groups_devices_write(struct file *file,
1581                                         const char __user *buf,
1582                                         size_t length, loff_t *off)
1583 {
1584         int res, action, virt = 0, rc, read_only = 0;
1585         char *buffer, *p, *e = NULL;
1586         unsigned int host, channel = 0, id = 0, lun = 0, virt_lun;
1587         struct scst_acg *acg =
1588                 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1589         struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
1590         struct scst_device *d, *dev = NULL;
1591
1592         TRACE_ENTRY();
1593
1594         if (length > SCST_PROC_BLOCK_SIZE) {
1595                 res = -EOVERFLOW;
1596                 goto out;
1597         }
1598         if (!buf) {
1599                 res = -EINVAL;
1600                 goto out;
1601         }
1602         buffer = (char *)__get_free_page(GFP_KERNEL);
1603         if (!buffer) {
1604                 res = -ENOMEM;
1605                 goto out;
1606         }
1607         if (copy_from_user(buffer, buf, length)) {
1608                 res = -EFAULT;
1609                 goto out_free;
1610         }
1611         if (length < PAGE_SIZE) {
1612                 buffer[length] = '\0';
1613         } else if (buffer[PAGE_SIZE-1]) {
1614                 res = -EINVAL;
1615                 goto out_free;
1616         }
1617
1618         /*
1619          * Usage: echo "add|del H:C:I:L lun [READ_ONLY]" \
1620          *          >/proc/scsi_tgt/groups/GROUP_NAME/devices
1621          *   or   echo "replace H:C:I:L lun [READ_ONLY]" \
1622          *          >/proc/scsi_tgt/groups/GROUP_NAME/devices
1623          *   or   echo "add|del V_NAME lun [READ_ONLY]" \
1624          *          >/proc/scsi_tgt/groups/GROUP_NAME/devices
1625          *   or   echo "replace V_NAME lun [READ_ONLY]" \
1626          *          >/proc/scsi_tgt/groups/GROUP_NAME/devices
1627          *   or   echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/devices
1628          */
1629         p = buffer;
1630         if (p[strlen(p) - 1] == '\n')
1631                 p[strlen(p) - 1] = '\0';
1632         if (!strncasecmp("clear", p, 5)) {
1633                 action = SCST_PROC_ACTION_CLEAR;
1634         } else if (!strncasecmp("add ", p, 4)) {
1635                 p += 4;
1636                 action = SCST_PROC_ACTION_ADD;
1637         } else if (!strncasecmp("del ", p, 4)) {
1638                 p += 4;
1639                 action = SCST_PROC_ACTION_DEL;
1640         } else if (!strncasecmp("replace ", p, 8)) {
1641                 p += 8;
1642                 action = SCST_PROC_ACTION_REPLACE;
1643         } else {
1644                 PRINT_ERROR("Unknown action \"%s\"", p);
1645                 res = -EINVAL;
1646                 goto out_free;
1647         }
1648
1649         res = scst_suspend_activity(true);
1650         if (res != 0)
1651                 goto out_free;
1652
1653         if (mutex_lock_interruptible(&scst_mutex) != 0) {
1654                 res = -EINTR;
1655                 goto out_free_resume;
1656         }
1657
1658         res = length;
1659
1660         switch (action) {
1661         case SCST_PROC_ACTION_ADD:
1662         case SCST_PROC_ACTION_DEL:
1663         case SCST_PROC_ACTION_REPLACE:
1664                 while (isspace(*p) && *p != '\0')
1665                         p++;
1666                 e = p; /* save p */
1667                 host = simple_strtoul(p, &p, 0);
1668                 if (*p == ':') {
1669                         channel = simple_strtoul(p + 1, &p, 0);
1670                         id = simple_strtoul(p + 1, &p, 0);
1671                         lun = simple_strtoul(p + 1, &p, 0);
1672                         e = p;
1673                 } else {
1674                         virt++;
1675                         p = e; /* restore p */
1676                         while (!isspace(*e) && *e != '\0')
1677                                 e++;
1678                         *e = 0;
1679                 }
1680
1681                 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1682                         if (virt) {
1683                                 if (d->virt_id && !strcmp(d->virt_name, p)) {
1684                                         dev = d;
1685                                         TRACE_DBG("Virt device %p (%s) found",
1686                                                   dev, p);
1687                                         break;
1688                                 }
1689                         } else {
1690                                 if (d->scsi_dev &&
1691                                     d->scsi_dev->host->host_no == host &&
1692                                     d->scsi_dev->channel == channel &&
1693                                     d->scsi_dev->id == id &&
1694                                     d->scsi_dev->lun == lun) {
1695                                         dev = d;
1696                                         TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
1697                                                   dev, host, channel, id, lun);
1698                                         break;
1699                                 }
1700                         }
1701                 }
1702                 if (dev == NULL) {
1703                         if (virt) {
1704                                 PRINT_ERROR("Virt device %s not found", p);
1705                         } else {
1706                                 PRINT_ERROR("Device %d:%d:%d:%d not found",
1707                                                host, channel, id, lun);
1708                         }
1709                         res = -EINVAL;
1710                         goto out_free_up;
1711                 }
1712                 break;
1713         }
1714
1715         /* ToDo: create separate functions */
1716
1717         switch (action) {
1718         case SCST_PROC_ACTION_ADD:
1719         case SCST_PROC_ACTION_REPLACE:
1720         {
1721                 bool dev_replaced = false;
1722
1723                 e++;
1724                 while (isspace(*e) && *e != '\0')
1725                         e++;
1726                 virt_lun = simple_strtoul(e, &e, 0);
1727
1728                 while (isspace(*e) && *e != '\0')
1729                         e++;
1730
1731                 if (*e != '\0') {
1732                         if (!strncasecmp("READ_ONLY", e, 9))
1733                                 read_only = 1;
1734                         else {
1735                                 PRINT_ERROR("Unknown option \"%s\"", e);
1736                                 res = -EINVAL;
1737                                 goto out_free_up;
1738                         }
1739                 }
1740
1741                 list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
1742                                     acg_dev_list_entry) {
1743                         if (acg_dev_tmp->lun == virt_lun) {
1744                                 acg_dev = acg_dev_tmp;
1745                                 break;
1746                         }
1747                 }
1748                 if (acg_dev != NULL) {
1749                         if (action == SCST_PROC_ACTION_ADD) {
1750                                 PRINT_ERROR("virt lun %d already exists in "
1751                                         "group %s", virt_lun, acg->acg_name);
1752                                 res = -EINVAL;
1753                                 goto out_free_up;
1754                         } else {
1755                                 /* Replace */
1756                                 rc = scst_acg_remove_dev(acg, acg_dev->dev,
1757                                                 false);
1758                                 if (rc) {
1759                                         res = rc;
1760                                         goto out_free_up;
1761                                 }
1762                                 dev_replaced = true;
1763                         }
1764                 }
1765
1766                 rc = scst_acg_add_dev(acg, dev, virt_lun, read_only,
1767                         action == SCST_PROC_ACTION_ADD);
1768                 if (rc) {
1769                         res = rc;
1770                         goto out_free_up;
1771                 }
1772
1773                 if (dev_replaced) {
1774                         struct scst_tgt_dev *tgt_dev;
1775
1776                         list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
1777                                         dev_tgt_dev_list_entry) {
1778                                 if ((tgt_dev->acg_dev->acg == acg) &&
1779                                     (tgt_dev->lun == virt_lun)) {
1780                                         TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED"
1781                                                 " on tgt_dev %p", tgt_dev);
1782                                         scst_gen_aen_or_ua(tgt_dev,
1783                                                 SCST_LOAD_SENSE(scst_sense_inquery_data_changed));
1784                                 }
1785                         }
1786                 }
1787                 break;
1788         }
1789         case SCST_PROC_ACTION_DEL:
1790                 rc = scst_acg_remove_dev(acg, dev, true);
1791                 if (rc) {
1792                         res = rc;
1793                         goto out_free_up;
1794                 }
1795                 break;
1796         case SCST_PROC_ACTION_CLEAR:
1797                 list_for_each_entry_safe(acg_dev, acg_dev_tmp,
1798                                          &acg->acg_dev_list,
1799                                          acg_dev_list_entry) {
1800                         rc = scst_acg_remove_dev(acg, acg_dev->dev,
1801                                 list_is_last(&acg_dev->acg_dev_list_entry,
1802                                              &acg->acg_dev_list));
1803                         if (rc) {
1804                                 res = rc;
1805                                 goto out_free_up;
1806                         }
1807                 }
1808                 break;
1809         }
1810
1811 out_free_up:
1812         mutex_unlock(&scst_mutex);
1813
1814 out_free_resume:
1815         scst_resume_activity();
1816
1817 out_free:
1818         free_page((unsigned long)buffer);
1819
1820 out:
1821         TRACE_EXIT_RES(res);
1822         return res;
1823 }
1824
1825 static ssize_t scst_proc_groups_names_write(struct file *file,
1826                                         const char __user *buf,
1827                                         size_t length, loff_t *off)
1828 {
1829         int res = length, rc = 0, action;
1830         char *buffer, *p, *pp = NULL;
1831         struct scst_acg *acg =
1832                 (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
1833         struct scst_acn *n, *nn;
1834
1835         TRACE_ENTRY();
1836
1837         if (length > SCST_PROC_BLOCK_SIZE) {
1838                 res = -EOVERFLOW;
1839                 goto out;
1840         }
1841         if (!buf) {
1842                 res = -EINVAL;
1843                 goto out;
1844         }
1845         buffer = (char *)__get_free_page(GFP_KERNEL);
1846         if (!buffer) {
1847                 res = -ENOMEM;
1848                 goto out;
1849         }
1850         if (copy_from_user(buffer, buf, length)) {
1851                 res = -EFAULT;
1852                 goto out_free;
1853         }
1854         if (length < PAGE_SIZE) {
1855                 buffer[length] = '\0';
1856         } else if (buffer[PAGE_SIZE-1]) {
1857                 res = -EINVAL;
1858                 goto out_free;
1859         }
1860
1861         /*
1862          * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP_NAME/names
1863          *   or   echo "move NAME NEW_GROUP_NAME" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names"
1864          *   or   echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/names
1865          */
1866         p = buffer;
1867         if (p[strlen(p) - 1] == '\n')
1868                 p[strlen(p) - 1] = '\0';
1869         if (!strncasecmp("clear", p, 5)) {
1870                 action = SCST_PROC_ACTION_CLEAR;
1871         } else if (!strncasecmp("add ", p, 4)) {
1872                 p += 4;
1873                 action = SCST_PROC_ACTION_ADD;
1874         } else if (!strncasecmp("del ", p, 4)) {
1875                 p += 4;
1876                 action = SCST_PROC_ACTION_DEL;
1877         } else if (!strncasecmp("move ", p, 5)) {
1878                 p += 5;
1879                 action = SCST_PROC_ACTION_MOVE;
1880         } else {
1881                 PRINT_ERROR("Unknown action \"%s\"", p);
1882                 res = -EINVAL;
1883                 goto out_free;
1884         }
1885
1886         switch (action) {
1887         case SCST_PROC_ACTION_ADD:
1888         case SCST_PROC_ACTION_DEL:
1889         case SCST_PROC_ACTION_MOVE:
1890                 while (isspace(*p) && *p != '\0')
1891                         p++;
1892                 pp = p;
1893                 while (!isspace(*pp) && *pp != '\0')
1894                         pp++;
1895                 if (*pp != '\0') {
1896                         *pp = '\0';
1897                         pp++;
1898                         while (isspace(*pp) && *pp != '\0')
1899                                 pp++;
1900                         if (*pp != '\0') {
1901                                 switch (action) {
1902                                 case SCST_PROC_ACTION_ADD:
1903                                 case SCST_PROC_ACTION_DEL:
1904                                         PRINT_ERROR("%s", "Too many "
1905                                                 "arguments");
1906                                         res = -EINVAL;
1907                                         goto out_free;
1908                                 }
1909                         }
1910                 }
1911                 break;
1912         }
1913
1914         rc = scst_suspend_activity(true);
1915         if (rc != 0)
1916                 goto out_free;
1917
1918         if (mutex_lock_interruptible(&scst_mutex) != 0) {
1919                 res = -EINTR;
1920                 goto out_free_resume;
1921         }
1922
1923         switch (action) {
1924         case SCST_PROC_ACTION_ADD:
1925                 rc = scst_acg_add_name(acg, p);
1926                 break;
1927         case SCST_PROC_ACTION_DEL:
1928                 rc = scst_acg_remove_name(acg, p, true);
1929                 break;
1930         case SCST_PROC_ACTION_MOVE:
1931         {
1932                 struct scst_acg *a, *new_acg = NULL;
1933                 char *name = p;
1934                 p = pp;
1935                 while (!isspace(*pp) && *pp != '\0')
1936                         pp++;
1937                 if (*pp != '\0') {
1938                         *pp = '\0';
1939                         pp++;
1940                         while (isspace(*pp) && *pp != '\0')
1941                                 pp++;
1942                         if (*pp != '\0') {
1943                                 PRINT_ERROR("%s", "Too many arguments");
1944                                 res = -EINVAL;
1945                                 goto out_free_unlock;
1946                         }
1947                 }
1948                 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1949                         if (strcmp(a->acg_name, p) == 0) {
1950                                 TRACE_DBG("group (acg) %p %s found",
1951                                           a, a->acg_name);
1952                                 new_acg = a;
1953                                 break;
1954                         }
1955                 }
1956                 if (new_acg == NULL) {
1957                         PRINT_ERROR("Group %s not found", p);
1958                         res = -EINVAL;
1959                         goto out_free_unlock;
1960                 }
1961                 rc = scst_acg_remove_name(acg, name, false);
1962                 if (rc != 0)
1963                         goto out_free_unlock;
1964                 rc = scst_acg_add_name(new_acg, name);
1965                 break;
1966         }
1967         case SCST_PROC_ACTION_CLEAR:
1968                 list_for_each_entry_safe(n, nn, &acg->acn_list,
1969                                          acn_list_entry) {
1970                         __scst_acg_remove_acn(n);
1971                 }
1972                 scst_check_reassign_sessions();
1973                 break;
1974         }
1975
1976 out_free_unlock:
1977         mutex_unlock(&scst_mutex);
1978
1979 out_free_resume:
1980         scst_resume_activity();
1981
1982 out_free:
1983         free_page((unsigned long)buffer);
1984
1985 out:
1986         if (rc < 0)
1987                 res = rc;
1988
1989         TRACE_EXIT_RES(res);
1990         return res;
1991 }
1992
1993 static int scst_version_info_show(struct seq_file *seq, void *v)
1994 {
1995         TRACE_ENTRY();
1996
1997         seq_printf(seq, "%s\n", SCST_VERSION_STRING);
1998
1999 #ifdef CONFIG_SCST_STRICT_SERIALIZING
2000         seq_printf(seq, "Strict serializing enabled\n");
2001 #endif
2002
2003 #ifdef CONFIG_SCST_EXTRACHECKS
2004         seq_printf(seq, "EXTRACHECKS\n");
2005 #endif
2006
2007 #ifdef CONFIG_SCST_TRACING
2008         seq_printf(seq, "TRACING\n");
2009 #endif
2010
2011 #ifdef CONFIG_SCST_DEBUG
2012         seq_printf(seq, "DEBUG\n");
2013 #endif
2014
2015 #ifdef CONFIG_SCST_DEBUG_TM
2016         seq_printf(seq, "DEBUG_TM\n");
2017 #endif
2018
2019 #ifdef CONFIG_SCST_DEBUG_RETRY
2020         seq_printf(seq, "DEBUG_RETRY\n");
2021 #endif
2022
2023 #ifdef CONFIG_SCST_DEBUG_OOM
2024         seq_printf(seq, "DEBUG_OOM\n");
2025 #endif
2026
2027 #ifdef CONFIG_SCST_DEBUG_SN
2028         seq_printf(seq, "DEBUG_SN\n");
2029 #endif
2030
2031 #ifdef CONFIG_SCST_USE_EXPECTED_VALUES
2032         seq_printf(seq, "USE_EXPECTED_VALUES\n");
2033 #endif
2034
2035 #ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
2036         seq_printf(seq, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
2037 #endif
2038
2039 #ifdef CONFIG_SCST_STRICT_SECURITY
2040         seq_printf(seq, "SCST_STRICT_SECURITY\n");
2041 #endif
2042
2043         TRACE_EXIT();
2044         return 0;
2045 }
2046
2047 static struct scst_proc_data scst_version_proc_data = {
2048         SCST_DEF_RW_SEQ_OP(NULL)
2049         .show = scst_version_info_show,
2050 };
2051
2052 static int scst_help_info_show(struct seq_file *seq, void *v)
2053 {
2054         TRACE_ENTRY();
2055
2056         seq_printf(seq, "%s\n", scst_proc_help_string);
2057
2058         TRACE_EXIT();
2059         return 0;
2060 }
2061
2062 static struct scst_proc_data scst_help_proc_data = {
2063         SCST_DEF_RW_SEQ_OP(NULL)
2064         .show = scst_help_info_show,
2065 };
2066
2067 static int scst_dev_handler_type_info_show(struct seq_file *seq, void *v)
2068 {
2069         struct scst_dev_type *dev_type = (struct scst_dev_type *)seq->private;
2070
2071         TRACE_ENTRY();
2072
2073         seq_printf(seq, "%d - %s\n", dev_type->type,
2074                    dev_type->type > (int)ARRAY_SIZE(scst_proc_dev_handler_type)
2075                    ? "unknown" : scst_proc_dev_handler_type[dev_type->type]);
2076
2077         TRACE_EXIT();
2078         return 0;
2079 }
2080
2081 static struct scst_proc_data scst_dev_handler_type_proc_data = {
2082         SCST_DEF_RW_SEQ_OP(NULL)
2083         .show = scst_dev_handler_type_info_show,
2084 };
2085
2086 static int scst_sessions_info_show(struct seq_file *seq, void *v)
2087 {
2088         int res = 0;
2089         struct scst_acg *acg;
2090         struct scst_session *sess;
2091
2092         TRACE_ENTRY();
2093
2094         if (mutex_lock_interruptible(&scst_mutex) != 0) {
2095                 res = -EINTR;
2096                 goto out;
2097         }
2098
2099         seq_printf(seq, "%-20s %-45s %-35s %-15s\n",
2100                    "Target name", "Initiator name",
2101                    "Group name", "Command Count");
2102
2103         list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
2104                 list_for_each_entry(sess, &acg->acg_sess_list,
2105                         acg_sess_list_entry) {
2106                         seq_printf(seq, "%-20s %-45s %-35s %-15d\n",
2107                                         sess->tgt->tgtt->name,
2108                                         sess->initiator_name,
2109                                         acg->acg_name,
2110                                         atomic_read(&sess->sess_cmd_count));
2111                 }
2112         }
2113
2114         mutex_unlock(&scst_mutex);
2115
2116 out:
2117         TRACE_EXIT_RES(res);
2118         return res;
2119 }
2120
2121 static struct scst_proc_data scst_sessions_proc_data = {
2122         SCST_DEF_RW_SEQ_OP(NULL)
2123         .show = scst_sessions_info_show,
2124 };
2125
2126
2127 static struct scst_proc_data scst_sgv_proc_data = {
2128         SCST_DEF_RW_SEQ_OP(NULL)
2129         .show = sgv_procinfo_show,
2130 };
2131
2132 static int scst_groups_names_show(struct seq_file *seq, void *v)
2133 {
2134         int res = 0;
2135         struct scst_acg *acg = (struct scst_acg *)seq->private;
2136         struct scst_acn *name;
2137
2138         TRACE_ENTRY();
2139
2140         if (mutex_lock_interruptible(&scst_mutex) != 0) {
2141                 res = -EINTR;
2142                 goto out;
2143         }
2144
2145         list_for_each_entry(name, &acg->acn_list, acn_list_entry) {
2146                 seq_printf(seq, "%s\n", name->name);
2147         }
2148
2149         mutex_unlock(&scst_mutex);
2150
2151 out:
2152         TRACE_EXIT_RES(res);
2153         return res;
2154 }
2155
2156 static struct scst_proc_data scst_groups_names_proc_data = {
2157         SCST_DEF_RW_SEQ_OP(scst_proc_groups_names_write)
2158         .show = scst_groups_names_show,
2159 };
2160
2161 static int scst_groups_devices_show(struct seq_file *seq, void *v)
2162 {
2163         int res = 0;
2164         struct scst_acg *acg = (struct scst_acg *)seq->private;
2165         struct scst_acg_dev *acg_dev;
2166
2167         TRACE_ENTRY();
2168
2169         if (mutex_lock_interruptible(&scst_mutex) != 0) {
2170                 res = -EINTR;
2171                 goto out;
2172         }
2173
2174         seq_printf(seq, "%-60s%-13s%s\n", "Device (host:ch:id:lun or name)",
2175                        "LUN", "Options");
2176
2177         list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
2178                 if (acg_dev->dev->virt_id == 0) {
2179                         char conv[60];
2180                         int size = sizeof(conv);
2181
2182                         memset(conv, 0, size);
2183                         size = snprintf(conv, size, "%d:%d:%d:",
2184                                         acg_dev->dev->scsi_dev->host->host_no,
2185                                         acg_dev->dev->scsi_dev->channel,
2186                                         acg_dev->dev->scsi_dev->id);
2187                         seq_printf(seq, "%s", conv);
2188
2189                         /*
2190                          * For some reason the third string argument always
2191                          * shown as NULL, so we have to split it on 2 calls.
2192                          */
2193                         sprintf(conv, "%%-%dd%%-13d", 60 - size);
2194                         size += seq_printf(seq, conv,
2195                                         acg_dev->dev->scsi_dev->lun,
2196                                         acg_dev->lun);
2197                         seq_printf(seq, "%s\n",
2198                                 acg_dev->rd_only ? "RO" : "");
2199                 } else {
2200                         seq_printf(seq, "%-60s%-13lld%s\n",
2201                                        acg_dev->dev->virt_name,
2202                                        (long long unsigned int)acg_dev->lun,
2203                                        acg_dev->rd_only ? "RO" : "");
2204                 }
2205         }
2206         mutex_unlock(&scst_mutex);
2207
2208 out:
2209         TRACE_EXIT_RES(res);
2210         return res;
2211 }
2212
2213 static struct scst_proc_data scst_groups_devices_proc_data = {
2214         SCST_DEF_RW_SEQ_OP(scst_proc_groups_devices_write)
2215         .show = scst_groups_devices_show,
2216 };
2217
2218 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2219
2220 static int scst_proc_read_tlb(const struct scst_proc_log *tbl,
2221                               struct seq_file *seq,
2222         unsigned long log_level, int *first)
2223 {
2224         const struct scst_proc_log *t = tbl;
2225         int res = 0;
2226
2227         while (t->token) {
2228                 if (log_level & t->val) {
2229                         seq_printf(seq, "%s%s", *first ? "" : " | ", t->token);
2230                         *first = 0;
2231                 }
2232                 t++;
2233         }
2234         return res;
2235 }
2236
2237 int scst_proc_log_entry_read(struct seq_file *seq, unsigned long log_level,
2238                              const struct scst_proc_log *tbl)
2239 {
2240         int res = 0, first = 1;
2241
2242         TRACE_ENTRY();
2243
2244         scst_proc_read_tlb(scst_proc_trace_tbl, seq, log_level, &first);
2245
2246         if (tbl)
2247                 scst_proc_read_tlb(tbl, seq, log_level, &first);
2248
2249         seq_printf(seq, "%s\n", first ? "none" : "");
2250
2251         TRACE_EXIT_RES(res);
2252         return res;
2253 }
2254 EXPORT_SYMBOL(scst_proc_log_entry_read);
2255
2256 static int log_info_show(struct seq_file *seq, void *v)
2257 {
2258         int res;
2259
2260         TRACE_ENTRY();
2261
2262         if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
2263                 res = -EINTR;
2264                 goto out;
2265         }
2266
2267         res = scst_proc_log_entry_read(seq, trace_flag,
2268                                        scst_proc_local_trace_tbl);
2269
2270         mutex_unlock(&scst_log_mutex);
2271
2272 out:
2273         TRACE_EXIT_RES(res);
2274         return res;
2275 }
2276
2277 static struct scst_proc_data scst_log_proc_data = {
2278         SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_log)
2279         .show = log_info_show,
2280         .data = "scsi_tgt",
2281 };
2282
2283 #endif
2284
2285 static int scst_tgt_info_show(struct seq_file *seq, void *v)
2286 {
2287         int res = 0;
2288         struct scst_device *dev;
2289
2290         TRACE_ENTRY();
2291
2292         if (mutex_lock_interruptible(&scst_mutex) != 0) {
2293                 res = -EINTR;
2294                 goto out;
2295         }
2296
2297         seq_printf(seq, "%-60s%s\n", "Device (host:ch:id:lun or name)",
2298                    "Device handler");
2299         list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
2300                 if (dev->virt_id == 0) {
2301                         char conv[60];
2302                         int size = sizeof(conv);
2303                         size = snprintf(conv, size, "%d:%d:%d:",
2304                                         dev->scsi_dev->host->host_no,
2305                                         dev->scsi_dev->channel,
2306                                         dev->scsi_dev->id);
2307                         seq_printf(seq, "%s", conv);
2308                         sprintf(conv, "%%-%dd%%s\n", 60 - size);
2309                         seq_printf(seq, conv, dev->scsi_dev->lun,
2310                                    dev->handler ? dev->handler->name : "-");
2311                 } else
2312                         seq_printf(seq, "%-60s%s\n",
2313                                    dev->virt_name, dev->handler->name);
2314         }
2315
2316         mutex_unlock(&scst_mutex);
2317
2318 out:
2319         TRACE_EXIT_RES(res);
2320         return res;
2321 }
2322
2323 static struct scst_proc_data scst_tgt_proc_data = {
2324         SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write)
2325         .show = scst_tgt_info_show,
2326 };
2327
2328 static int scst_threads_info_show(struct seq_file *seq, void *v)
2329 {
2330         TRACE_ENTRY();
2331
2332         seq_printf(seq, "%d\n", scst_global_threads_count());
2333
2334         TRACE_EXIT();
2335         return 0;
2336 }
2337
2338 static struct scst_proc_data scst_threads_proc_data = {
2339         SCST_DEF_RW_SEQ_OP(scst_proc_threads_write)
2340         .show = scst_threads_info_show,
2341 };
2342
2343 static int scst_scsi_tgtinfo_show(struct seq_file *seq, void *v)
2344 {
2345         struct scst_tgt *vtt = seq->private;
2346         int res = 0;
2347
2348         TRACE_ENTRY();
2349
2350         if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2351                 res = -EINTR;
2352                 goto out;
2353         }
2354
2355         if (vtt->tgtt->read_proc)
2356                 res = vtt->tgtt->read_proc(seq, vtt);
2357
2358         mutex_unlock(&scst_proc_mutex);
2359 out:
2360         TRACE_EXIT_RES(res);
2361         return res;
2362 }
2363
2364 static struct scst_proc_data scst_scsi_tgt_proc_data = {
2365         SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_write)
2366         .show = scst_scsi_tgtinfo_show,
2367 };
2368
2369 static int scst_dev_handler_info_show(struct seq_file *seq, void *v)
2370 {
2371         struct scst_dev_type *dev_type = seq->private;
2372         int res = 0;
2373
2374         TRACE_ENTRY();
2375
2376         if (mutex_lock_interruptible(&scst_proc_mutex) != 0) {
2377                 res = -EINTR;
2378                 goto out;
2379         }
2380
2381         if (dev_type->read_proc)
2382                 res = dev_type->read_proc(seq, dev_type);
2383
2384         mutex_unlock(&scst_proc_mutex);
2385
2386 out:
2387         TRACE_EXIT_RES(res);
2388         return res;
2389 }
2390
2391 static struct scst_proc_data scst_dev_handler_proc_data = {
2392         SCST_DEF_RW_SEQ_OP(scst_proc_scsi_dev_handler_write)
2393         .show = scst_dev_handler_info_show,
2394 };
2395
2396 struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry *root,
2397         const char *name, struct scst_proc_data *pdata)
2398 {
2399         struct proc_dir_entry *p = NULL;
2400
2401         TRACE_ENTRY();
2402
2403         if (root) {
2404                 mode_t mode;
2405
2406                 mode = S_IFREG | S_IRUGO | (pdata->seq_op.write ? S_IWUSR : 0);
2407                 p = create_proc_entry(name, mode, root);
2408                 if (p == NULL) {
2409                         PRINT_ERROR("Fail to create entry %s in /proc", name);
2410                 } else {
2411                         p->proc_fops = &pdata->seq_op;
2412                         p->data = pdata->data;
2413                 }
2414         }
2415
2416         TRACE_EXIT();
2417         return p;
2418 }
2419 EXPORT_SYMBOL(scst_create_proc_entry);
2420
2421 int scst_single_seq_open(struct inode *inode, struct file *file)
2422 {
2423 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
2424         struct scst_proc_data *pdata = container_of(PDE(inode)->proc_fops,
2425                 struct scst_proc_data, seq_op);
2426 #else
2427         struct scst_proc_data *pdata = container_of(inode->i_fop,
2428                 struct scst_proc_data, seq_op);
2429 #endif
2430         return single_open(file, pdata->show, PDE(inode)->data);
2431 }
2432 EXPORT_SYMBOL(scst_single_seq_open);