4 * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, version 2
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
18 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/list.h>
24 #include <linux/spinlock.h>
25 #include <linux/slab.h>
26 #include <linux/sched.h>
27 #include <asm/unistd.h>
28 #include <asm/string.h>
29 #include <asm/uaccess.h>
30 #include <linux/proc_fs.h>
32 #include "scst_debug.h"
35 #include "scst_priv.h"
37 static int scst_scsi_tgt_proc_info(char *buffer, char **start,
38 off_t offset, int length, int *eof,
40 static int scst_proc_scsi_tgt_gen_write(struct file *file,
42 unsigned long length, void *data);
43 static int scst_proc_version_read(char *buffer, char **start,off_t offset,
44 int length, int *eof, void *data);
45 static int scst_proc_sessions_read(char *buffer, char **start, off_t offset,
46 int length, int *eof, void *data);
47 static int scst_proc_help_read(char *buffer, char **start,off_t offset,
48 int length, int *eof, void *data);
49 static int scst_proc_threads_read(char *buffer, char **start,off_t offset,
50 int length, int *eof, void *data);
51 static int scst_proc_threads_write(struct file *file, const char *buf,
52 unsigned long length, void *data);
53 static int scst_proc_scsi_tgt_read(char *buffer, char **start, off_t offset,
54 int length, int *eof, void *data);
55 static int scst_proc_scsi_tgt_write(struct file *file, const char *buf,
56 unsigned long count, void *data);
57 static int scst_proc_scsi_dev_handler_read(char *buffer, char **start,
58 off_t offset, int length, int *eof,
60 static int scst_proc_scsi_dev_handler_write(struct file *file, const char *buf,
61 unsigned long count, void *data);
62 static int scst_proc_scsi_dev_handler_type_read(char *buffer, char **start,
63 off_t offset, int length,
64 int *eof, void *data);
65 static int scst_proc_init_groups(void);
66 static void scst_proc_cleanup_groups(void);
67 static int scst_proc_assign_handler(char *buf);
68 static int scst_proc_group_add(const char *p);
69 static int scst_proc_groups_devices_read(char *buffer, char **start,
70 off_t offset, int length, int *eof,
72 static int scst_proc_groups_devices_write(struct file *file, const char *buf,
73 unsigned long length, void *data);
74 static int scst_proc_groups_names_read(char *buffer, char **start,
75 off_t offset, int length, int *eof,
77 static int scst_proc_groups_names_write(struct file *file, const char *buf,
78 unsigned long length, void *data);
79 static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc);
82 * Must be less than 4K page size, since our output routines
83 * use some slack for overruns
85 #define SCST_PROC_BLOCK_SIZE (PAGE_SIZE - 512)
87 #define SCST_PROC_LOG_ENTRY_NAME "trace_level"
88 #define SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME "type"
89 #define SCST_PROC_VERSION_NAME "version"
90 #define SCST_PROC_SESSIONS_NAME "sessions"
91 #define SCST_PROC_HELP_NAME "help"
92 #define SCST_PROC_THREADS_NAME "threads"
93 #define SCST_PROC_GROUPS_ENTRY_NAME "groups"
94 #define SCST_PROC_GROUPS_DEVICES_ENTRY_NAME "devices"
95 #define SCST_PROC_GROUPS_USERS_ENTRY_NAME "names"
97 #define SCST_PROC_ACTION_ALL 1
98 #define SCST_PROC_ACTION_NONE 2
99 #define SCST_PROC_ACTION_DEFAULT 3
100 #define SCST_PROC_ACTION_SET 4
101 #define SCST_PROC_ACTION_ADD 5
102 #define SCST_PROC_ACTION_CLEAR 6
103 #define SCST_PROC_ACTION_DEL 7
104 #define SCST_PROC_ACTION_VALUE 8
105 #define SCST_PROC_ACTION_ASSIGN 9
106 #define SCST_PROC_ACTION_ADD_GROUP 10
107 #define SCST_PROC_ACTION_DEL_GROUP 11
109 static struct proc_dir_entry *scst_proc_scsi_tgt;
110 static struct proc_dir_entry *scst_proc_groups_root;
112 #if defined(DEBUG) || defined(TRACING)
113 static struct scst_proc_log scst_proc_trace_tbl[] =
115 { TRACE_OUT_OF_MEM, "out_of_mem" },
116 { TRACE_MINOR, "minor" },
118 { TRACE_MEMORY, "mem" },
119 { TRACE_BUFF, "buff" },
120 { TRACE_ENTRYEXIT, "entryexit" },
121 { TRACE_PID, "pid" },
122 { TRACE_LINE, "line" },
123 { TRACE_FUNCTION, "function" },
124 { TRACE_DEBUG, "debug" },
125 { TRACE_SPECIAL, "special" },
126 { TRACE_SCSI, "scsi" },
127 { TRACE_MGMT, "mgmt" },
128 { TRACE_MGMT_DEBUG, "mgmt_dbg" },
132 static struct scst_proc_log scst_proc_local_trace_tbl[] =
134 { TRACE_RETRY, "retry" },
135 { TRACE_SCSI_SERIALIZING, "scsi_serializing" },
136 { TRACE_RECV_BOT, "recv_bot" },
137 { TRACE_SEND_BOT, "send_bot" },
138 { TRACE_RECV_TOP, "recv_top" },
139 { TRACE_SEND_TOP, "send_top" },
144 static char *scst_proc_help_string =
145 " echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n"
147 " echo \"add_group GROUP\" >/proc/scsi_tgt/scsi_tgt\n"
148 " echo \"del_group GROUP\" >/proc/scsi_tgt/scsi_tgt\n"
150 " echo \"add|del H:C:I:L lun [READ_ONLY]\" >/proc/scsi_tgt/groups/GROUP/devices\n"
151 " echo \"add|del V_NAME lun [READ_ONLY]\" >/proc/scsi_tgt/groups/GROUP/devices\n"
152 " echo \"clear\" >/proc/scsi_tgt/groups/GROUP/devices\n"
154 " echo \"add|del NAME\" >/proc/scsi_tgt/groups/GROUP/names\n"
155 " echo \"clear\" >/proc/scsi_tgt/groups/GROUP/names\n"
157 " echo \"DEC|0xHEX|0OCT\" >/proc/scsi_tgt/threads\n"
158 #if defined(DEBUG) || defined(TRACING)
160 " echo \"all|none|default\" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
161 " echo \"value DEC|0xHEX|0OCT\" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
162 " echo \"set|add|del TOKEN\" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n"
163 " where TOKEN is one of [debug,function,line,pid,entryexit,\n"
164 " buff,mem,sg,out_of_mem,special,scsi,mgmt,minor]\n"
165 " Additionally for /proc/scsi_tgt/trace_level there are these TOKENs\n"
166 " [scsi_serializing,retry,recv_bot,send_bot,recv_top,send_top]\n"
170 static char *scst_proc_dev_handler_type[] =
172 "Direct-access device (e.g., magnetic disk)",
173 "Sequential-access device (e.g., magnetic tape)",
176 "Write-once device (e.g., some optical disks)",
178 "Scanner device (obsolete)",
179 "Optical memory device (e.g., some optical disks)",
180 "Medium changer device (e.g., jukeboxes)",
181 "Communications device (obsolete)",
182 "Defined by ASC IT8 (Graphic arts pre-press devices)",
183 "Defined by ASC IT8 (Graphic arts pre-press devices)",
184 "Storage array controller device (e.g., RAID)",
185 "Enclosure services device",
186 "Simplified direct-access device (e.g., magnetic disk)",
187 "Optical card reader/writer device"
190 static DECLARE_MUTEX(scst_proc_mutex);
192 #include <linux/ctype.h>
194 #if !defined(CONFIG_PPC)
196 #if defined(DEBUG) || defined(TRACING)
197 static int strcasecmp(const char *s1, const char *s2)
203 } while (c1 == c2 && c1 != 0);
208 static int strncasecmp(const char *s1, const char *s2, int n)
214 } while ((--n > 0) && c1 == c2 && c1 != 0);
218 #endif /* CONFIG_PPC */
220 int scst_proc_read_tlb(const struct scst_proc_log *tbl, char *buffer,
221 int length, off_t offset, unsigned long log_level, int *first,
222 int *size, int *len, off_t *begin, off_t *pos)
224 const struct scst_proc_log *t = tbl;
228 if (log_level & t->val) {
229 *size = scnprintf(buffer + *len, length - *len,
230 "%s%s", *first ? "" : " | ", t->token);
234 *pos = *begin + *len;
235 if (*pos <= offset) {
238 } else if (*pos >= offset + length)
253 #if defined(DEBUG) || defined(TRACING)
255 int scst_proc_log_entry_read(char *buffer, char **start,
256 off_t offset, int length, int *eof, void *data,
257 unsigned long log_level,
258 const struct scst_proc_log *tbl)
260 int res = 0, first = 1;
262 off_t begin = 0, pos = 0;
266 TRACE_DBG("offset: %d, length %d", (int) offset, length);
268 if (scst_proc_read_tlb(scst_proc_trace_tbl, buffer, length, offset,
269 log_level, &first, &size, &len, &begin, &pos))
273 TRACE_DBG("Reading private tlb, offset: %d, length %d",
274 (int) offset, length);
275 if (scst_proc_read_tlb(tbl, buffer, length, offset,
276 log_level, &first, &size, &len, &begin, &pos))
280 size = scnprintf(buffer + len, length - len, "%s\n", first ? "none" : "");
287 } else if (pos >= offset + length)
293 *start = buffer + (offset - begin);
294 len -= (offset - begin);
302 int scst_proc_log_entry_write(struct file *file, const char *buf,
303 unsigned long length, void *data, unsigned long *log_level,
304 unsigned long default_level, const struct scst_proc_log *tbl)
308 unsigned long level = 0, oldlevel;
309 char *buffer, *p, *e;
310 const struct scst_proc_log *t;
314 if (length > SCST_PROC_BLOCK_SIZE) {
322 buffer = (char *)__get_free_page(GFP_KERNEL);
327 if (copy_from_user(buffer, buf, length)) {
331 if (length < PAGE_SIZE) {
332 buffer[length] = '\0';
333 } else if (buffer[PAGE_SIZE-1]) {
340 * echo "all|none|default" >/proc/scsi_tgt/trace_log_level
341 * echo "value DEC|0xHEX|0OCT" >/proc/scsi_tgt/trace_log_level
342 * echo "set|add|clear|del TOKEN" >/proc/scsi_tgt/trace_log_level
343 * where TOKEN is one of [debug,function,line,pid,entryexit,
344 * buff,mem,sg,out_of_mem,retry,
345 * scsi_serializing,special,scsi,mgmt,minor,...]
348 if (!strncasecmp("all", p, 3)) {
349 action = SCST_PROC_ACTION_ALL;
350 } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) {
351 action = SCST_PROC_ACTION_NONE;
352 } else if (!strncasecmp("default", p, 7)) {
353 action = SCST_PROC_ACTION_DEFAULT;
354 } else if (!strncasecmp("set ", p, 4)) {
356 action = SCST_PROC_ACTION_SET;
357 } else if (!strncasecmp("add ", p, 4)) {
359 action = SCST_PROC_ACTION_ADD;
360 } else if (!strncasecmp("del ", p, 4)) {
362 action = SCST_PROC_ACTION_DEL;
363 } else if (!strncasecmp("value ", p, 6)) {
365 action = SCST_PROC_ACTION_VALUE;
367 if (p[strlen(p) - 1] == '\n') {
368 p[strlen(p) - 1] = '\0';
370 PRINT_ERROR_PR("Unknown action \"%s\"", p);
376 case SCST_PROC_ACTION_ALL:
379 case SCST_PROC_ACTION_DEFAULT:
380 level = default_level;
382 case SCST_PROC_ACTION_NONE:
385 case SCST_PROC_ACTION_SET:
386 case SCST_PROC_ACTION_ADD:
387 case SCST_PROC_ACTION_DEL:
388 while (isspace(*p) && *p != '\0') {
392 while (!isspace(*e) && *e != '\0') {
399 if (!strcasecmp(p, t->token)) {
407 t = scst_proc_trace_tbl;
409 if (!strcasecmp(p, t->token)) {
417 PRINT_ERROR("Unknown token \"%s\"", p);
422 case SCST_PROC_ACTION_VALUE:
423 while (isspace(*p) && *p != '\0') {
426 level = simple_strtoul(p, NULL, 0);
430 oldlevel = *log_level;
433 case SCST_PROC_ACTION_ADD:
436 case SCST_PROC_ACTION_DEL:
437 *log_level &= ~level;
444 PRINT_INFO("Changed trace level for \"%s\": "
445 "old 0x%08lx, new 0x%08lx",
446 (char *)data, oldlevel, *log_level);
449 free_page((unsigned long)buffer);
455 static int scst_scsi_tgt_proc_info_log(char *buffer, char **start,
456 off_t offset, int length, int *eof,
464 if (down_interruptible(&scst_proc_mutex) != 0) {
469 res = scst_proc_log_entry_read(buffer, start, offset, length, eof,
470 data, trace_flag, scst_proc_local_trace_tbl);
472 up(&scst_proc_mutex);
479 static int scst_proc_scsi_tgt_gen_write_log(struct file *file,
481 unsigned long length, void *data)
487 if (down_interruptible(&scst_proc_mutex) != 0) {
492 res = scst_proc_log_entry_write(file, buf, length, data,
493 &trace_flag, SCST_DEFAULT_LOG_FLAGS, scst_proc_local_trace_tbl);
495 up(&scst_proc_mutex);
502 #endif /* defined(DEBUG) || defined(TRACING) */
504 static int scst_proc_init_module_log(void)
507 #if defined(DEBUG) || defined(TRACING)
508 struct proc_dir_entry *generic;
512 generic = create_proc_read_entry(SCST_PROC_LOG_ENTRY_NAME,
513 S_IFREG | S_IRUGO | S_IWUSR,
515 scst_scsi_tgt_proc_info_log,
518 generic->write_proc = scst_proc_scsi_tgt_gen_write_log;
520 PRINT_ERROR_PR("cannot init /proc/%s/%s",
521 SCST_PROC_ENTRY_NAME, SCST_PROC_LOG_ENTRY_NAME);
530 static void scst_proc_cleanup_module_log(void)
532 #if defined(DEBUG) || defined(TRACING)
535 remove_proc_entry(SCST_PROC_LOG_ENTRY_NAME, scst_proc_scsi_tgt);
541 static int scst_proc_group_add_tree(struct scst_acg *acg, const char *p)
544 struct proc_dir_entry *generic;
548 acg->acg_proc_root = proc_mkdir(p, scst_proc_groups_root);
549 if (acg->acg_proc_root == NULL) {
550 PRINT_ERROR_PR("Not enough memory to register %s entry in "
551 "/proc/%s/%s", p, SCST_PROC_ENTRY_NAME,
552 SCST_PROC_GROUPS_ENTRY_NAME);
556 generic = create_proc_read_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
557 S_IFREG | S_IRUGO | S_IWUSR,
559 scst_proc_groups_devices_read,
562 generic->write_proc = scst_proc_groups_devices_write;
564 PRINT_ERROR_PR("cannot init /proc/%s/%s/%s/%s",
565 SCST_PROC_ENTRY_NAME,
566 SCST_PROC_GROUPS_ENTRY_NAME,
567 p, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME);
572 generic = create_proc_read_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME,
573 S_IFREG | S_IRUGO | S_IWUSR,
575 scst_proc_groups_names_read,
578 generic->write_proc = scst_proc_groups_names_write;
580 PRINT_ERROR_PR("cannot init /proc/%s/%s/%s/%s",
581 SCST_PROC_ENTRY_NAME,
582 SCST_PROC_GROUPS_ENTRY_NAME,
583 p, SCST_PROC_GROUPS_USERS_ENTRY_NAME);
593 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
597 remove_proc_entry(p, scst_proc_groups_root);
601 static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
606 remove_proc_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME, acg_proc_root);
607 remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME,
609 remove_proc_entry(name, scst_proc_groups_root);
615 static int scst_proc_group_add(const char *p)
617 int res = 0, len = strlen(p) + 1;
618 struct scst_acg *acg;
623 name = kmalloc(len, GFP_KERNEL);
625 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of name failed");
628 strncpy(name, p, len);
630 acg = scst_alloc_add_acg(name);
632 PRINT_ERROR_PR("scst_alloc_add_acg() (name %s) failed", name);
636 res = scst_proc_group_add_tree(acg, p);
645 scst_proc_del_free_acg(acg, 0);
655 static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc)
658 struct proc_dir_entry *acg_proc_root = acg->acg_proc_root;
663 if (acg != scst_default_acg) {
664 name = acg->acg_name;
665 res = scst_destroy_acg(acg);
668 scst_proc_del_acg_tree(acg_proc_root, name);
677 static int scst_proc_init_groups(void)
683 /* create the proc directory entry for the device */
684 scst_proc_groups_root = proc_mkdir(SCST_PROC_GROUPS_ENTRY_NAME,
686 if (scst_proc_groups_root == NULL) {
687 PRINT_ERROR_PR("Not enough memory to register %s entry in "
688 "/proc/%s", SCST_PROC_GROUPS_ENTRY_NAME,
689 SCST_PROC_ENTRY_NAME);
693 res = scst_proc_group_add_tree(scst_default_acg,
694 SCST_DEFAULT_ACG_NAME);
703 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
710 static void scst_proc_cleanup_groups(void)
712 struct scst_acg *acg_tmp, *acg;
716 /* remove all groups (dir & entries) */
717 list_for_each_entry_safe(acg, acg_tmp, &scst_acg_list,
718 scst_acg_list_entry) {
719 scst_proc_del_free_acg(acg, 1);
722 scst_proc_del_acg_tree(scst_default_acg->acg_proc_root,
723 SCST_DEFAULT_ACG_NAME);
724 TRACE_DBG("remove_proc_entry(%s, %p)",
725 SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
726 remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt);
731 struct scst_proc_update_struct {
732 int len, plen, pplen;
733 off_t begin, pbegin, ppbegin;
737 static int scst_proc_update_size(int size, off_t offset, int length,
738 struct scst_proc_update_struct *p)
743 p->pos = p->begin + p->len;
744 if (p->pos <= offset) {
747 } else if (p->pos >= offset + length) {
753 p->begin = p->ppbegin;
758 p->ppbegin = p->pbegin;
760 p->pbegin = p->begin;
766 static int scst_proc_sgv_read_1(char *buffer, off_t offset, int length,
767 struct scst_proc_update_struct *p,
768 const struct sgv_pool *pool, const char *name)
772 size = scnprintf(buffer + p->len, length - p->len, "\n%-20s %-11d %-11d\n",
773 name, atomic_read(&pool->acc.hit_alloc),
774 atomic_read(&pool->acc.total_alloc));
775 if (scst_proc_update_size(size, offset, length, p))
778 for(i = 0; i < SGV_POOL_ELEMENTS; i++) {
779 size = scnprintf(buffer + p->len, length - p->len,
780 " %-18s %-11d %-11d\n", pool->cache_names[i],
781 atomic_read(&pool->cache_acc[i].hit_alloc),
782 atomic_read(&pool->cache_acc[i].total_alloc));
783 if (scst_proc_update_size(size, offset, length, p))
789 static int scst_proc_sgv_read(char *buffer, char **start,
790 off_t offset, int length, int *eof, void *data)
794 struct scst_proc_update_struct st;
798 TRACE_DBG("offset: %d, length %d", (int) offset, length);
800 memset(&st, 0, sizeof(st));
802 size = scnprintf(buffer + st.len, length - st.len, "%-20s %-11s %-11s",
803 "Name", "Hit", "Total");
804 if (scst_proc_update_size(size, offset, length, &st))
807 if (scst_proc_sgv_read_1(buffer, offset, length, &st, &scst_sgv.norm,
811 if (scst_proc_sgv_read_1(buffer, offset, length, &st,
812 &scst_sgv.norm_clust, "sgv-clust"))
815 if (scst_proc_sgv_read_1(buffer, offset, length, &st,
816 &scst_sgv.dma, "sgv-dma"))
820 if (scst_proc_sgv_read_1(buffer, offset, length, &st,
821 &scst_sgv.highmem, "sgv-highmem"))
826 size = scnprintf(buffer + st.len, length - st.len, "\n%-32s %-11d\n",
827 "big", atomic_read(&sgv_big_total_alloc));
828 if (scst_proc_update_size(size, offset, length, &st))
834 *start = buffer + (offset - st.begin);
835 st.len -= (offset - st.begin);
838 res = max(0, st.len);
844 static int scst_proc_init_sgv(void)
847 struct proc_dir_entry *pr;
851 pr = create_proc_read_entry("sgv", S_IFREG | S_IRUGO,
852 scst_proc_scsi_tgt, scst_proc_sgv_read, NULL);
854 PRINT_ERROR_PR("%s", "cannot create sgv /proc entry");
862 static void scst_proc_cleanup_sgv(void)
865 remove_proc_entry("sgv", scst_proc_scsi_tgt);
869 int scst_proc_init_module(void)
872 struct proc_dir_entry *generic;
876 scst_proc_scsi_tgt = proc_mkdir(SCST_PROC_ENTRY_NAME, 0);
877 if (!scst_proc_scsi_tgt) {
878 PRINT_ERROR_PR("cannot init /proc/%s", SCST_PROC_ENTRY_NAME);
882 generic = create_proc_read_entry(SCST_PROC_ENTRY_NAME,
883 S_IFREG | S_IRUGO | S_IWUSR,
885 scst_scsi_tgt_proc_info, NULL);
887 PRINT_ERROR_PR("cannot init /proc/%s/%s",
888 SCST_PROC_ENTRY_NAME, SCST_PROC_ENTRY_NAME);
891 generic->write_proc = scst_proc_scsi_tgt_gen_write;
893 generic = create_proc_read_entry(SCST_PROC_VERSION_NAME,
896 scst_proc_version_read, NULL);
898 PRINT_ERROR_PR("cannot init /proc/%s/%s",
899 SCST_PROC_ENTRY_NAME, SCST_PROC_VERSION_NAME);
903 generic = create_proc_read_entry(SCST_PROC_SESSIONS_NAME,
906 scst_proc_sessions_read, NULL);
908 PRINT_ERROR_PR("cannot init /proc/%s/%s",
909 SCST_PROC_ENTRY_NAME, SCST_PROC_SESSIONS_NAME);
913 generic = create_proc_read_entry(SCST_PROC_HELP_NAME,
916 scst_proc_help_read, NULL);
918 PRINT_ERROR_PR("cannot init /proc/%s/%s",
919 SCST_PROC_ENTRY_NAME, SCST_PROC_HELP_NAME);
923 generic = create_proc_read_entry(SCST_PROC_THREADS_NAME,
924 S_IFREG | S_IRUGO | S_IWUSR,
926 scst_proc_threads_read, NULL);
928 PRINT_ERROR_PR("cannot init /proc/%s/%s",
929 SCST_PROC_ENTRY_NAME, SCST_PROC_THREADS_NAME);
932 generic->write_proc = scst_proc_threads_write;
934 if (scst_proc_init_module_log() < 0) {
938 if (scst_proc_init_groups() < 0) {
942 if (scst_proc_init_sgv() < 0) {
951 scst_proc_cleanup_groups();
954 scst_proc_cleanup_module_log();
957 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
960 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
963 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
966 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
969 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
972 remove_proc_entry(SCST_PROC_ENTRY_NAME, 0);
979 void scst_proc_cleanup_module(void)
983 /* We may not bother about locks here */
984 scst_proc_cleanup_sgv();
985 scst_proc_cleanup_groups();
986 scst_proc_cleanup_module_log();
987 remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt);
988 remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt);
989 remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt);
990 remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt);
991 remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt);
992 remove_proc_entry(SCST_PROC_ENTRY_NAME, 0);
997 static int scst_scsi_tgt_proc_info(char *buffer, char **start,
998 off_t offset, int length, int *eof,
1002 int size, len = 0, plen, pplen;
1003 off_t begin = 0, pos = 0, pbegin, ppbegin;
1004 struct scst_device *dev;
1008 //TRACE(TRACE_SPECIAL, "offset=%ld, length=%d", offset, length);
1010 if (down_interruptible(&scst_mutex) != 0) {
1015 size = scnprintf(buffer + len, length - len, "%-60s%s\n",
1016 "Device (host:ch:id:lun or name)",
1019 //TRACE(TRACE_SPECIAL, "size=%d, pos=%ld, begin=%ld, len=%d, buf %s",
1020 // size, pos, begin, len, buffer+len);
1025 if (pos <= offset) {
1028 } else if (pos >= offset + length)
1033 ppbegin = pbegin = begin;
1035 list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
1036 if (dev->virt_id == 0) {
1038 size = scnprintf(buffer + len, length - len,
1040 dev->scsi_dev->host->host_no,
1041 dev->scsi_dev->channel,
1043 sprintf(conv, "%%-%dd%%s\n", 60-size);
1044 size += scnprintf(buffer + len + size, length - len - size,
1045 conv, dev->scsi_dev->lun,
1046 dev->handler ? dev->handler->name : "-");
1048 size = scnprintf(buffer + len, length - len,
1050 dev->virt_name, dev->handler->name);
1053 //printk("size=%d, pbegin=%ld, plen=%d, ppbegin=%ld, pplen=%d, buf %s",
1054 // size, pbegin, plen, ppbegin, pplen, buffer+len);
1059 if (pos <= offset) {
1063 //TRACE(TRACE_SPECIAL, "pos=%ld, begin=%ld, len=%d", pos, begin, len);
1064 if (pos >= offset + length)
1080 *start = buffer + (offset - begin);
1081 len -= (offset - begin);
1086 //TRACE(TRACE_SPECIAL, "res=%d, start=%ld, len=%d, begin=%ld, eof=%d", res, offset-begin, len, begin, *eof);
1091 TRACE_EXIT_RES(res);
1095 static int scst_proc_version_read(char *buffer, char **start,off_t offset,
1096 int length, int *eof, void *data)
1102 res = scnprintf(buffer, length, "%s\n", SCST_VERSION_STRING);
1104 #ifdef STRICT_SERIALIZING
1106 res += scnprintf(&buffer[res], length-res, "Strict "
1107 "serializing enabled\n");
1112 res += scnprintf(&buffer[res], length-res, "EXTRACHECKS\n");
1117 res += scnprintf(&buffer[res], length-res, "TRACING\n");
1122 res += scnprintf(&buffer[res], length-res, "DEBUG\n");
1127 res += scnprintf(&buffer[res], length-res, "DEBUG_TM\n");
1132 res += scnprintf(&buffer[res], length-res, "DEBUG_RETRY\n");
1137 res += scnprintf(&buffer[res], length-res, "DEBUG_OOM\n");
1140 TRACE_EXIT_RES(res);
1144 static int scst_proc_help_read(char *buffer, char **start, off_t offset,
1145 int length, int *eof, void *data)
1151 res = scnprintf(buffer, length, "%s", scst_proc_help_string);
1153 TRACE_EXIT_RES(res);
1157 static int scst_proc_threads_read(char *buffer, char **start,off_t offset,
1158 int length, int *eof, void *data)
1164 /* 2 mgmt threads */
1165 res = scnprintf(buffer, length, "%d\n",
1166 atomic_read(&scst_threads_count) - 2);
1168 TRACE_EXIT_RES(res);
1172 static int scst_proc_threads_write(struct file *file, const char *buf,
1173 unsigned long length, void *data)
1176 int oldtn, newtn, delta;
1182 if (length > SCST_PROC_BLOCK_SIZE) {
1190 buffer = (char *)__get_free_page(GFP_KERNEL);
1195 if (copy_from_user(buffer, buf, length)) {
1199 if (length < PAGE_SIZE) {
1200 buffer[length] = '\0';
1201 } else if (buffer[PAGE_SIZE-1]) {
1206 if (down_interruptible(&scst_proc_mutex) != 0) {
1211 oldtn = atomic_read(&scst_threads_count);
1212 newtn = simple_strtoul(buffer, NULL, 0) + 2; /* 2 mgmt threads */
1214 PRINT_ERROR_PR("Illegal threads num value %d", newtn);
1218 delta = newtn - oldtn;
1220 scst_del_threads(-delta);
1223 scst_add_threads(delta);
1226 PRINT_INFO_PR("Changed threads num: old %d, new %d(%d)", oldtn, newtn,
1227 atomic_read(&scst_threads_count));
1230 up(&scst_proc_mutex);
1233 free_page((unsigned long)buffer);
1235 TRACE_EXIT_RES(res);
1239 int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt)
1245 /* create the proc directory entry for the device */
1246 vtt->proc_tgt_root = proc_mkdir(vtt->name, scst_proc_scsi_tgt);
1247 if (vtt->proc_tgt_root == NULL) {
1248 PRINT_ERROR_PR("Not enough memory to register SCSI target %s "
1249 "in /proc/%s", vtt->name, SCST_PROC_ENTRY_NAME);
1254 TRACE_EXIT_RES(res);
1262 void scst_cleanup_proc_target_dir_entries(struct scst_tgt_template *vtt)
1266 remove_proc_entry(vtt->name, scst_proc_scsi_tgt);
1272 int scst_build_proc_target_entries(struct scst_tgt *vtt)
1275 struct proc_dir_entry *p;
1280 if (vtt->tgtt->proc_info) {
1281 /* create the proc file entry for the device */
1282 scnprintf(name, sizeof(name), "%d", vtt->tgtt->proc_dev_num);
1283 p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
1284 vtt->tgtt->proc_tgt_root,
1285 scst_proc_scsi_tgt_read,
1288 PRINT_ERROR_PR("Not enough memory to register SCSI "
1289 "target entry %s in /proc/%s/%s", name,
1290 SCST_PROC_ENTRY_NAME, vtt->tgtt->name);
1294 p->write_proc = scst_proc_scsi_tgt_write;
1295 vtt->proc_num = vtt->tgtt->proc_dev_num;
1296 vtt->tgtt->proc_dev_num++;
1300 TRACE_EXIT_RES(res);
1304 void scst_cleanup_proc_target_entries(struct scst_tgt *vtt)
1310 if (vtt->tgtt->proc_info) {
1311 scnprintf(name, sizeof(name), "%d", vtt->proc_num);
1312 remove_proc_entry(name, vtt->tgtt->proc_tgt_root);
1319 static int scst_proc_scsi_tgt_read(char *buffer, char **start,
1320 off_t offset, int length, int *eof,
1323 struct scst_tgt *vtt = data;
1328 TRACE_DBG("offset: %d, length %d, id: %d",
1329 (int) offset, length, vtt->proc_num);
1331 if (down_interruptible(&scst_proc_mutex) != 0) {
1336 if (vtt->tgtt->proc_info) {
1337 res = vtt->tgtt->proc_info(buffer, start, offset, length, eof,
1341 up(&scst_proc_mutex);
1344 TRACE_EXIT_RES(res);
1348 static int scst_proc_scsi_tgt_write(struct file *file, const char *buf,
1349 unsigned long length, void *data)
1351 struct scst_tgt *vtt = data;
1359 if (vtt->tgtt->proc_info == NULL) {
1364 if (length > SCST_PROC_BLOCK_SIZE) {
1372 buffer = (char *)__get_free_page(GFP_KERNEL);
1377 if (copy_from_user(buffer, buf, length)) {
1381 if (length < PAGE_SIZE) {
1382 buffer[length] = '\0';
1383 } else if (buffer[PAGE_SIZE-1]) {
1388 TRACE_BUFFER("Buffer", buffer, length);
1390 if (down_interruptible(&scst_proc_mutex) != 0) {
1395 res = vtt->tgtt->proc_info(buffer, &start, 0, length, &eof, vtt, 1);
1397 up(&scst_proc_mutex);
1400 free_page((unsigned long)buffer);
1402 TRACE_EXIT_RES(res);
1406 int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1409 struct proc_dir_entry *p;
1413 if (dev_type->proc_dev_type_root) {
1416 /* create the proc directory entry for the dev type handler */
1417 dev_type->proc_dev_type_root = proc_mkdir(dev_type->name,
1418 scst_proc_scsi_tgt);
1419 if (dev_type->proc_dev_type_root == NULL) {
1420 PRINT_ERROR_PR("Not enough memory to register dev handler dir "
1421 "%s in /proc/%s", dev_type->name, SCST_PROC_ENTRY_NAME);
1425 p = create_proc_read_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1427 dev_type->proc_dev_type_root,
1428 scst_proc_scsi_dev_handler_type_read,
1431 PRINT_ERROR_PR("Not enough memory to register dev "
1432 "handler entry %s in /proc/%s/%s",
1433 SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1434 SCST_PROC_ENTRY_NAME, dev_type->name);
1438 if (dev_type->proc_info) {
1439 /* create the proc file entry for the dev type handler */
1440 p = create_proc_read_entry(dev_type->name,
1441 S_IFREG | S_IRUGO | S_IWUSR,
1442 dev_type->proc_dev_type_root,
1443 scst_proc_scsi_dev_handler_read,
1446 PRINT_ERROR_PR("Not enough memory to register dev "
1447 "handler entry %s in /proc/%s/%s", dev_type->name,
1448 SCST_PROC_ENTRY_NAME, dev_type->name);
1451 p->write_proc = scst_proc_scsi_dev_handler_write;
1455 TRACE_EXIT_RES(res);
1459 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1460 dev_type->proc_dev_type_root);
1463 remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1470 void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
1474 if (dev_type->proc_dev_type_root) {
1475 remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
1476 dev_type->proc_dev_type_root);
1477 if (dev_type->proc_info) {
1478 remove_proc_entry(dev_type->name,
1479 dev_type->proc_dev_type_root);
1481 remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
1482 dev_type->proc_dev_type_root = NULL;
1489 static int scst_proc_scsi_dev_handler_type_read(char *buffer, char **start,
1490 off_t offset, int length,
1491 int *eof, void *data)
1493 struct scst_dev_type *dev_type = data;
1498 n = scnprintf(buffer, length, "%d - %s\n", dev_type->type,
1499 dev_type->type > 0x0f ?
1500 "unknown" : scst_proc_dev_handler_type[dev_type->type]);
1506 static int scst_proc_scsi_dev_handler_read(char *buffer, char **start,
1507 off_t offset, int length, int *eof,
1510 struct scst_dev_type *dev_type = data;
1515 TRACE_DBG("offset: %d, length %d, name: %s",
1516 (int) offset, length, dev_type->name);
1518 if (down_interruptible(&scst_proc_mutex) != 0) {
1523 if (dev_type->proc_info) {
1524 res = dev_type->proc_info(buffer, start, offset, length, eof,
1528 up(&scst_proc_mutex);
1531 TRACE_EXIT_RES(res);
1535 static int scst_proc_scsi_dev_handler_write(struct file *file, const char *buf,
1536 unsigned long length, void *data)
1538 struct scst_dev_type *dev_type = data;
1546 if (dev_type->proc_info == NULL) {
1551 if (length > SCST_PROC_BLOCK_SIZE) {
1560 if (!(buffer = (char *)__get_free_page(GFP_KERNEL))) {
1565 if (copy_from_user(buffer, buf, length)) {
1569 if (length < PAGE_SIZE) {
1570 buffer[length] = '\0';
1571 } else if (buffer[PAGE_SIZE-1]) {
1576 TRACE_BUFFER("Buffer", buffer, length);
1578 if (down_interruptible(&scst_proc_mutex) != 0) {
1583 res = dev_type->proc_info(buffer, &start, 0, length, &eof, dev_type, 1);
1585 up(&scst_proc_mutex);
1588 free_page((unsigned long)buffer);
1591 TRACE_EXIT_RES(res);
1595 static int scst_proc_scsi_tgt_gen_write(struct file *file,
1597 unsigned long length, void *data)
1599 int res = length, rc = 0, action;
1601 struct scst_acg *a, *acg = NULL;
1605 if (length > SCST_PROC_BLOCK_SIZE) {
1613 buffer = (char *)__get_free_page(GFP_KERNEL);
1618 if (copy_from_user(buffer, buf, length)) {
1622 if (length < PAGE_SIZE) {
1623 buffer[length] = '\0';
1624 } else if (buffer[PAGE_SIZE-1]) {
1630 * Usage: echo "add_group GROUP" >/proc/scsi_tgt/scsi_tgt
1631 * or echo "del_group GROUP" >/proc/scsi_tgt/scsi_tgt
1632 * or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt
1635 if (p[strlen(p) - 1] == '\n') {
1636 p[strlen(p) - 1] = '\0';
1638 if (!strncasecmp("assign ", p, 7)) {
1640 action = SCST_PROC_ACTION_ASSIGN;
1641 } else if (!strncasecmp("add_group ", p, 10)) {
1643 action = SCST_PROC_ACTION_ADD_GROUP;
1644 } else if (!strncasecmp("del_group ", p, 10)) {
1646 action = SCST_PROC_ACTION_DEL_GROUP;
1648 PRINT_ERROR_PR("Unknown action \"%s\"", p);
1653 if (down_interruptible(&scst_mutex) != 0) {
1659 case SCST_PROC_ACTION_ADD_GROUP:
1660 case SCST_PROC_ACTION_DEL_GROUP:
1661 if (strcmp(p, SCST_DEFAULT_ACG_NAME) == 0) {
1662 PRINT_ERROR_PR("Attempt to add/delete predefined "
1667 list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) {
1668 if (strcmp(a->acg_name, p) == 0) {
1669 TRACE_DBG("group (acg) %p %s found",
1676 case SCST_PROC_ACTION_ADD_GROUP:
1678 PRINT_ERROR_PR("acg name %s exist", p);
1682 rc = scst_proc_group_add(p);
1684 case SCST_PROC_ACTION_DEL_GROUP:
1686 PRINT_ERROR_PR("acg name %s not found", p);
1690 rc = scst_proc_del_free_acg(acg, 1);
1694 case SCST_PROC_ACTION_ASSIGN:
1695 rc = scst_proc_assign_handler(p);
1706 free_page((unsigned long)buffer);
1708 TRACE_EXIT_RES(res);
1712 /* Called under scst_mutex */
1713 static int scst_proc_assign_handler(char *buf)
1716 char *p = buf, *e, *ee;
1717 int host, channel = 0, id = 0, lun = 0;
1718 struct scst_device *d, *dev = NULL;
1719 struct scst_dev_type *dt, *handler = NULL;
1723 while (isspace(*p) && *p != '\0') {
1727 host = simple_strtoul(p, &p, 0);
1728 if ((host == ULONG_MAX) || (*p != ':'))
1731 channel = simple_strtoul(p, &p, 0);
1732 if ((channel == ULONG_MAX) || (*p != ':'))
1735 id = simple_strtoul(p, &p, 0);
1736 if ((channel == ULONG_MAX) || (*p != ':'))
1739 lun = simple_strtoul(p, &p, 0);
1740 if (lun == ULONG_MAX)
1745 while (isspace(*e) && *e != '\0') {
1749 while (!isspace(*ee) && *ee != '\0') {
1754 TRACE_DBG("Dev %d:%d:%d:%d, handler %s", host, channel, id, lun, e);
1756 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1757 if ((d->virt_id == 0) &&
1758 d->scsi_dev->host->host_no == host &&
1759 d->scsi_dev->channel == channel &&
1760 d->scsi_dev->id == id &&
1761 d->scsi_dev->lun == lun)
1764 TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
1765 dev, host, channel, id, lun);
1771 PRINT_ERROR_PR("Device %d:%d:%d:%d not found",
1772 host, channel, id, lun);
1777 list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
1778 if (!strcmp(dt->name, e)) {
1780 TRACE_DBG("Dev handler %p with name %s found",
1786 if (handler == NULL) {
1787 PRINT_ERROR_PR("Handler %s not found", e);
1792 if (dev->scsi_dev->type != handler->type) {
1793 PRINT_ERROR_PR("Type %d of device %s differs from type "
1794 "%d of dev handler %s", dev->handler->type,
1795 dev->handler->name, handler->type, handler->name);
1800 res = scst_assign_dev_handler(dev, handler);
1803 TRACE_EXIT_RES(res);
1807 PRINT_ERROR_PR("Syntax error on %s", p);
1812 static int scst_proc_groups_devices_read(char *buffer, char **start,
1813 off_t offset, int length, int *eof,
1817 struct scst_acg *acg = (struct scst_acg *)data;
1818 struct scst_acg_dev *acg_dev;
1819 int size, len = 0, plen, pplen;
1820 off_t begin = 0, pos = 0, pbegin, ppbegin;
1824 if (down_interruptible(&scst_mutex) != 0) {
1829 size = scnprintf(buffer + len, length - len, "%-60s%s %s\n",
1830 "Device (host:ch:id:lun or name)",
1831 "Virtual lun", "Options");
1835 if (pos <= offset) {
1838 } else if (pos >= offset + length)
1843 ppbegin = pbegin = begin;
1845 list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
1846 if (acg_dev->dev->virt_id == 0) {
1848 size = scnprintf(buffer + len, length - len,
1850 acg_dev->dev->scsi_dev->host->host_no,
1851 acg_dev->dev->scsi_dev->channel,
1852 acg_dev->dev->scsi_dev->id);
1853 sprintf(conv, "%%-%dd%%4d%%12s\n", 60-size);
1854 size += scnprintf(buffer + len + size,
1855 length - len - size, conv,
1856 acg_dev->dev->scsi_dev->lun,
1858 acg_dev->rd_only_flag ? "RO" : "");
1860 size = scnprintf(buffer + len, length - len,
1862 acg_dev->dev->virt_name, acg_dev->lun,
1863 acg_dev->rd_only_flag ? "RO" : "");
1868 if (pos <= offset) {
1871 } else if (pos >= offset + length)
1887 *start = buffer + (offset - begin);
1888 len -= (offset - begin);
1896 TRACE_EXIT_RES(res);
1900 static int scst_proc_groups_devices_write(struct file *file, const char *buf,
1901 unsigned long length, void *data)
1903 int res = length, action, virt = 0, rc, read_only = 0;
1904 char *buffer, *p, *e = NULL;
1905 int host, channel = 0, id = 0, lun = 0, virt_lun;
1906 struct scst_acg *acg = (struct scst_acg *)data;
1907 struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
1908 struct scst_device *d, *dev = NULL;
1912 if (length > SCST_PROC_BLOCK_SIZE) {
1920 buffer = (char *)__get_free_page(GFP_KERNEL);
1925 if (copy_from_user(buffer, buf, length)) {
1929 if (length < PAGE_SIZE) {
1930 buffer[length] = '\0';
1931 } else if (buffer[PAGE_SIZE-1]) {
1937 * Usage: echo "add|del H:C:I:L lun [READ_ONLY]" >/proc/scsi_tgt/groups/GROUP/devices
1938 * or echo "add|del V_NAME lun [READ_ONLY]" >/proc/scsi_tgt/groups/GROUP/devices
1939 * or echo "clear" >/proc/scsi_tgt/groups/GROUP/devices
1942 if (p[strlen(p) - 1] == '\n') {
1943 p[strlen(p) - 1] = '\0';
1945 if (!strncasecmp("clear", p, 5)) {
1946 action = SCST_PROC_ACTION_CLEAR;
1947 } else if (!strncasecmp("add ", p, 4)) {
1949 action = SCST_PROC_ACTION_ADD;
1950 } else if (!strncasecmp("del ", p, 4)) {
1952 action = SCST_PROC_ACTION_DEL;
1954 PRINT_ERROR_PR("Unknown action \"%s\"", p);
1959 if (down_interruptible(&scst_mutex) != 0) {
1965 case SCST_PROC_ACTION_ADD:
1966 case SCST_PROC_ACTION_DEL:
1967 while (isspace(*p) && *p != '\0') {
1971 host = simple_strtoul(p, &p, 0);
1973 channel = simple_strtoul(p + 1, &p, 0);
1974 id = simple_strtoul(p + 1, &p, 0);
1975 lun = simple_strtoul(p + 1, &p, 0);
1979 p = e; /* restore p */
1980 while (!isspace(*e) && *e != '\0') {
1986 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1988 if (d->virt_id && !strcmp(d->virt_name, p)) {
1990 TRACE_DBG("Virt device %p (%s) found",
1996 d->scsi_dev->host->host_no == host &&
1997 d->scsi_dev->channel == channel &&
1998 d->scsi_dev->id == id &&
1999 d->scsi_dev->lun == lun) {
2001 TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
2002 dev, host, channel, id, lun);
2009 PRINT_ERROR_PR("Virt device %s not found", p);
2011 PRINT_ERROR_PR("Device %d:%d:%d:%d not found",
2012 host, channel, id, lun);
2020 /* ToDo: create separate functions */
2023 case SCST_PROC_ACTION_ADD:
2025 while (isspace(*e) && *e != '\0') {
2028 virt_lun = simple_strtoul(e, &e, 0);
2030 while (isspace(*e) && *e != '\0') {
2033 if (!strncasecmp("READ_ONLY", e, 9)) {
2037 list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
2038 acg_dev_list_entry) {
2039 if (acg_dev_tmp->lun == virt_lun) {
2040 acg_dev = acg_dev_tmp;
2045 acg_dev = acg_dev_tmp;
2046 PRINT_ERROR_PR("virt lun %d exist in group %s",
2047 virt_lun, acg->acg_name);
2051 rc = scst_acg_add_dev(acg, dev, virt_lun, read_only);
2053 PRINT_ERROR_PR("scst_acg_add_dev() returned %d", rc);
2057 case SCST_PROC_ACTION_DEL:
2058 rc = scst_acg_remove_dev(acg, dev);
2060 PRINT_ERROR_PR("scst_acg_remove_dev() returned %d", rc);
2064 case SCST_PROC_ACTION_CLEAR:
2065 list_for_each_entry_safe(acg_dev, acg_dev_tmp,
2067 acg_dev_list_entry) {
2068 rc = scst_acg_remove_dev(acg, acg_dev->dev);
2070 PRINT_ERROR_PR("scst_acg_remove_dev() "
2082 free_page((unsigned long)buffer);
2084 TRACE_EXIT_RES(res);
2088 static int scst_proc_sessions_read(char *buffer, char **start,
2089 off_t offset, int length, int *eof,
2093 struct scst_acg *acg;
2094 struct scst_session *sess;
2095 int size, len = 0, plen, pplen;
2096 off_t begin = 0, pos = 0, pbegin, ppbegin;
2100 if (down_interruptible(&scst_mutex) != 0) {
2105 size = scnprintf(buffer + len, length - len, "%-20s%-35s%-20s%-15s\n",
2106 "Target name", "Initiator name", "Group name",
2111 if (pos <= offset) {
2114 } else if (pos >= offset + length)
2119 ppbegin = pbegin = begin;
2121 list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
2122 list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
2123 size = scnprintf(buffer + len, length - len,
2124 "%-20s%-35s%-20s%-15d\n",
2125 sess->tgt->tgtt->name,
2126 sess->initiator_name,
2128 sess->sess_cmd_count);
2132 if (pos <= offset) {
2135 } else if (pos >= offset + length)
2152 *start = buffer + (offset - begin);
2153 len -= (offset - begin);
2161 TRACE_EXIT_RES(res);
2165 static int scst_proc_groups_names_read(char *buffer, char **start,
2166 off_t offset, int length, int *eof,
2170 struct scst_acg *acg = (struct scst_acg *)data;
2171 struct scst_acn *name;
2172 int size, len = 0, plen, pplen;
2173 off_t begin = 0, pos = 0, pbegin, ppbegin;
2177 if (down_interruptible(&scst_mutex) != 0) {
2182 ppbegin = pbegin = begin;
2184 list_for_each_entry(name, &acg->acn_list, acn_list_entry) {
2185 size = scnprintf(buffer + len, length - len, "%s\n",
2190 if (pos <= offset) {
2193 } else if (pos >= offset + length)
2209 *start = buffer + (offset - begin);
2210 len -= (offset - begin);
2218 TRACE_EXIT_RES(res);
2222 static int scst_proc_groups_names_write(struct file *file, const char *buf,
2223 unsigned long length, void *data)
2225 int res = length, action;
2226 char *buffer, *p, *e;
2227 struct scst_acg *acg = (struct scst_acg *)data;
2228 struct scst_acn *n, *nn;
2232 if (length > SCST_PROC_BLOCK_SIZE) {
2240 buffer = (char *)__get_free_page(GFP_KERNEL);
2245 if (copy_from_user(buffer, buf, length)) {
2249 if (length < PAGE_SIZE) {
2250 buffer[length] = '\0';
2251 } else if (buffer[PAGE_SIZE-1]) {
2257 * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP/names
2258 * or echo "clear" >/proc/scsi_tgt/groups/GROUP/names
2261 if (p[strlen(p) - 1] == '\n') {
2262 p[strlen(p) - 1] = '\0';
2264 if (!strncasecmp("clear", p, 5)) {
2265 action = SCST_PROC_ACTION_CLEAR;
2266 } else if (!strncasecmp("add ", p, 4)) {
2268 action = SCST_PROC_ACTION_ADD;
2269 } else if (!strncasecmp("del ", p, 4)) {
2271 action = SCST_PROC_ACTION_DEL;
2273 PRINT_ERROR_PR("Unknown action \"%s\"", p);
2279 case SCST_PROC_ACTION_ADD:
2280 case SCST_PROC_ACTION_DEL:
2281 while (isspace(*p) && *p != '\0') {
2285 while (!isspace(*e) && *e != '\0') {
2292 if (down_interruptible(&scst_mutex) != 0) {
2298 case SCST_PROC_ACTION_ADD:
2299 scst_acg_add_name(acg, p);
2301 case SCST_PROC_ACTION_DEL:
2302 scst_acg_remove_name(acg, p);
2304 case SCST_PROC_ACTION_CLEAR:
2305 list_for_each_entry_safe(n, nn, &acg->acn_list,
2307 list_del(&n->acn_list_entry);
2317 free_page((unsigned long)buffer);
2319 TRACE_EXIT_RES(res);