Fix copy_to_user()/copy_from_user() wrong reeturn value processing
[mirror/scst/.git] / iscsi-scst / kernel / config.c
1 /*
2  *  Copyright (C) 2004 - 2005 FUJITA Tomonori <tomof@acm.org>
3  *  Copyright (C) 2007 - 2009 Vladislav Bolkhovitin
4  *  Copyright (C) 2007 - 2009 ID7 Ltd.
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  */
15
16 #include "iscsi.h"
17
18 /* Protected by target_mgmt_mutex */
19 int ctr_open_state;
20
21 #ifdef CONFIG_SCST_PROC
22
23 #include <linux/proc_fs.h>
24
25 #define ISCSI_PROC_VERSION_NAME         "version"
26
27 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
28
29 #define ISCSI_PROC_LOG_ENTRY_NAME       "trace_level"
30
31 static struct scst_trace_log iscsi_local_trace_tbl[] = {
32     { TRACE_D_WRITE,            "d_write" },
33     { TRACE_CONN_OC,            "conn" },
34     { TRACE_CONN_OC_DBG,        "conn_dbg" },
35     { TRACE_D_IOV,              "iov" },
36     { TRACE_D_DUMP_PDU,         "pdu" },
37     { TRACE_NET_PG,             "net_page" },
38     { 0,                        NULL }
39 };
40
41 static int iscsi_log_info_show(struct seq_file *seq, void *v)
42 {
43         int res = 0;
44
45         TRACE_ENTRY();
46
47         res = scst_proc_log_entry_read(seq, trace_flag,
48                 iscsi_local_trace_tbl);
49
50         TRACE_EXIT_RES(res);
51         return res;
52 }
53
54 static ssize_t iscsi_proc_log_entry_write(struct file *file,
55         const char __user *buf, size_t length, loff_t *off)
56 {
57         int res = 0;
58
59         TRACE_ENTRY();
60
61         res = scst_proc_log_entry_write(file, buf, length, &trace_flag,
62                 ISCSI_DEFAULT_LOG_FLAGS, iscsi_local_trace_tbl);
63
64         TRACE_EXIT_RES(res);
65         return res;
66 }
67
68 #endif /* DEBUG or TRACE */
69
70 static int iscsi_version_info_show(struct seq_file *seq, void *v)
71 {
72         TRACE_ENTRY();
73
74         seq_printf(seq, "%s\n", ISCSI_VERSION_STRING);
75
76 #ifdef CONFIG_SCST_EXTRACHECKS
77         seq_printf(seq, "EXTRACHECKS\n");
78 #endif
79
80 #ifdef CONFIG_SCST_TRACING
81         seq_printf(seq, "TRACING\n");
82 #endif
83
84 #ifdef CONFIG_SCST_DEBUG
85         seq_printf(seq, "DEBUG\n");
86 #endif
87
88 #ifdef CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES
89         seq_printf(seq, "DEBUG_DIGEST_FAILURES\n");
90 #endif
91
92         TRACE_EXIT();
93         return 0;
94 }
95
96 static struct scst_proc_data iscsi_version_proc_data = {
97         SCST_DEF_RW_SEQ_OP(NULL)
98         .show = iscsi_version_info_show,
99 };
100
101 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
102 static struct scst_proc_data iscsi_log_proc_data = {
103         SCST_DEF_RW_SEQ_OP(iscsi_proc_log_entry_write)
104         .show = iscsi_log_info_show,
105 };
106 #endif
107
108 static __init int iscsi_proc_log_entry_build(struct scst_tgt_template *templ)
109 {
110         int res = 0;
111         struct proc_dir_entry *p, *root;
112
113         TRACE_ENTRY();
114
115         root = scst_proc_get_tgt_root(templ);
116         if (root) {
117                 p = scst_create_proc_entry(root, ISCSI_PROC_VERSION_NAME,
118                                            &iscsi_version_proc_data);
119                 if (p == NULL) {
120                         PRINT_ERROR("Not enough memory to register "
121                              "target driver %s entry %s in /proc",
122                               templ->name, ISCSI_PROC_VERSION_NAME);
123                         res = -ENOMEM;
124                         goto out;
125                 }
126
127 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
128                 /* create the proc file entry for the device */
129                 iscsi_log_proc_data.data = (void *)templ->name;
130                 p = scst_create_proc_entry(root, ISCSI_PROC_LOG_ENTRY_NAME,
131                                            &iscsi_log_proc_data);
132                 if (p == NULL) {
133                         PRINT_ERROR("Not enough memory to register "
134                              "target driver %s entry %s in /proc",
135                               templ->name, ISCSI_PROC_LOG_ENTRY_NAME);
136                         res = -ENOMEM;
137                         goto out_remove_ver;
138                 }
139 #endif
140         }
141
142 out:
143         TRACE_EXIT_RES(res);
144         return res;
145
146 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
147 out_remove_ver:
148         remove_proc_entry(ISCSI_PROC_VERSION_NAME, root);
149         goto out;
150 #endif
151 }
152
153 static void iscsi_proc_log_entry_clean(struct scst_tgt_template *templ)
154 {
155         struct proc_dir_entry *root;
156
157         TRACE_ENTRY();
158
159         root = scst_proc_get_tgt_root(templ);
160         if (root) {
161 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
162                 remove_proc_entry(ISCSI_PROC_LOG_ENTRY_NAME, root);
163 #endif
164                 remove_proc_entry(ISCSI_PROC_VERSION_NAME, root);
165         }
166
167         TRACE_EXIT();
168         return;
169 }
170
171 struct proc_entries {
172         const char *name;
173         const struct file_operations *const fops;
174 };
175
176 static struct proc_entries iscsi_proc_entries[] = {
177         {"session", &session_seq_fops},
178 };
179
180 static struct proc_dir_entry *proc_iscsi_dir;
181
182 void iscsi_procfs_exit(void)
183 {
184         unsigned int i;
185
186         if (!proc_iscsi_dir)
187                 return;
188
189         for (i = 0; i < ARRAY_SIZE(iscsi_proc_entries); i++)
190                 remove_proc_entry(iscsi_proc_entries[i].name, proc_iscsi_dir);
191
192         iscsi_proc_log_entry_clean(&iscsi_template);
193 }
194
195 int __init iscsi_procfs_init(void)
196 {
197         unsigned int i;
198         int err = 0;
199         struct proc_dir_entry *ent;
200
201         proc_iscsi_dir = scst_proc_get_tgt_root(&iscsi_template);
202         if (proc_iscsi_dir == NULL) {
203                 err = -ESRCH;
204                 goto out;
205         }
206
207 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
208         proc_iscsi_dir->owner = THIS_MODULE;
209 #endif
210
211         err = iscsi_proc_log_entry_build(&iscsi_template);
212         if (err < 0)
213                 goto out;
214
215         for (i = 0; i < ARRAY_SIZE(iscsi_proc_entries); i++) {
216                 ent = create_proc_entry(iscsi_proc_entries[i].name, 0,
217                                         proc_iscsi_dir);
218                 if (ent)
219                         ent->proc_fops = iscsi_proc_entries[i].fops;
220                 else {
221                         err = -ENOMEM;
222                         goto err;
223                 }
224         }
225
226 out:
227         return err;
228
229 err:
230         if (proc_iscsi_dir)
231                 iscsi_procfs_exit();
232         goto out;
233 }
234
235 #else /* CONFIG_SCST_PROC */
236
237 /* Protected by target_mgmt_mutex */
238 static LIST_HEAD(iscsi_attrs_list);
239
240 static ssize_t iscsi_version_show(struct kobject *kobj,
241         struct kobj_attribute *attr, char *buf)
242 {
243         TRACE_ENTRY();
244
245         sprintf(buf, "%s\n", ISCSI_VERSION_STRING);
246
247 #ifdef CONFIG_SCST_EXTRACHECKS
248         strcat(buf, "EXTRACHECKS\n");
249 #endif
250
251 #ifdef CONFIG_SCST_TRACING
252         strcat(buf, "TRACING\n");
253 #endif
254
255 #ifdef CONFIG_SCST_DEBUG
256         strcat(buf, "DEBUG\n");
257 #endif
258
259 #ifdef CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES
260         strcat(buf, "DEBUG_DIGEST_FAILURES\n");
261 #endif
262
263         TRACE_EXIT();
264         return strlen(buf);
265 }
266
267 static struct kobj_attribute iscsi_version_attr =
268         __ATTR(version, S_IRUGO, iscsi_version_show, NULL);
269
270 static ssize_t iscsi_open_state_show(struct kobject *kobj,
271         struct kobj_attribute *attr, char *buf)
272 {
273         switch (ctr_open_state) {
274         case ISCSI_CTR_OPEN_STATE_CLOSED:
275                 sprintf(buf, "%s\n", "closed");
276                 break;
277         case ISCSI_CTR_OPEN_STATE_OPEN:
278                 sprintf(buf, "%s\n", "open");
279                 break;
280         case ISCSI_CTR_OPEN_STATE_CLOSING:
281                 sprintf(buf, "%s\n", "closing");
282                 break;
283         default:
284                 sprintf(buf, "%s\n", "unknown");
285                 break;
286         }
287
288         return strlen(buf);
289 }
290
291 static struct kobj_attribute iscsi_open_state_attr =
292         __ATTR(open_state, S_IRUGO, iscsi_open_state_show, NULL);
293
294 const struct attribute *iscsi_attrs[] = {
295         &iscsi_version_attr.attr,
296         &iscsi_open_state_attr.attr,
297         NULL,
298 };
299
300 #endif /* CONFIG_SCST_PROC */
301
302 /* target_mgmt_mutex supposed to be locked */
303 static int add_conn(void __user *ptr)
304 {
305         int err, rc;
306         struct iscsi_session *session;
307         struct iscsi_kern_conn_info info;
308         struct iscsi_target *target;
309
310         TRACE_ENTRY();
311
312         rc = copy_from_user(&info, ptr, sizeof(info));
313         if (rc != 0) {
314                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
315                 err = -EFAULT;
316                 goto out;
317         }
318
319         target = target_lookup_by_id(info.tid);
320         if (target == NULL) {
321                 PRINT_ERROR("Target %d not found", info.tid);
322                 err = -ENOENT;
323                 goto out;
324         }
325
326         mutex_lock(&target->target_mutex);
327
328         session = session_lookup(target, info.sid);
329         if (!session) {
330                 PRINT_ERROR("Session %lld not found",
331                         (long long unsigned int)info.tid);
332                 err = -ENOENT;
333                 goto out_unlock;
334         }
335
336         err = __add_conn(session, &info);
337
338 out_unlock:
339         mutex_unlock(&target->target_mutex);
340
341 out:
342         TRACE_EXIT_RES(err);
343         return err;
344 }
345
346 /* target_mgmt_mutex supposed to be locked */
347 static int del_conn(void __user *ptr)
348 {
349         int err, rc;
350         struct iscsi_session *session;
351         struct iscsi_kern_conn_info info;
352         struct iscsi_target *target;
353
354         TRACE_ENTRY();
355
356         rc = copy_from_user(&info, ptr, sizeof(info));
357         if (rc != 0) {
358                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
359                 err = -EFAULT;
360                 goto out;
361         }
362
363         target = target_lookup_by_id(info.tid);
364         if (target == NULL) {
365                 PRINT_ERROR("Target %d not found", info.tid);
366                 err = -ENOENT;
367                 goto out;
368         }
369
370         mutex_lock(&target->target_mutex);
371
372         session = session_lookup(target, info.sid);
373         if (!session) {
374                 PRINT_ERROR("Session %llx not found",
375                         (long long unsigned int)info.sid);
376                 err = -ENOENT;
377                 goto out_unlock;
378         }
379
380         err = __del_conn(session, &info);
381
382 out_unlock:
383         mutex_unlock(&target->target_mutex);
384
385 out:
386         TRACE_EXIT_RES(err);
387         return err;
388 }
389
390 /* target_mgmt_mutex supposed to be locked */
391 static int add_session(void __user *ptr)
392 {
393         int err, rc;
394         struct iscsi_kern_session_info *info;
395         struct iscsi_target *target;
396
397         TRACE_ENTRY();
398
399         info = kzalloc(sizeof(*info), GFP_KERNEL);
400         if (info == NULL) {
401                 PRINT_ERROR("Can't alloc info (size %d)", sizeof(*info));
402                 err = -ENOMEM;
403                 goto out;
404         }
405
406         rc = copy_from_user(info, ptr, sizeof(*info));
407         if (rc != 0) {
408                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
409                 err = -EFAULT;
410                 goto out_free;
411         }
412
413         info->initiator_name[sizeof(info->initiator_name)-1] = '\0';
414 #ifdef CONFIG_SCST_PROC
415         info->user_name[sizeof(info->user_name)-1] = '\0';
416 #endif
417
418         target = target_lookup_by_id(info->tid);
419         if (target == NULL) {
420                 PRINT_ERROR("Target %d not found", info->tid);
421                 err = -ENOENT;
422                 goto out_free;
423         }
424
425         err = __add_session(target, info);
426
427 out_free:
428         kfree(info);
429
430 out:
431         TRACE_EXIT_RES(err);
432         return err;
433 }
434
435 /* target_mgmt_mutex supposed to be locked */
436 static int del_session(void __user *ptr)
437 {
438         int err, rc;
439         struct iscsi_kern_session_info *info;
440         struct iscsi_target *target;
441
442         TRACE_ENTRY();
443
444         info = kzalloc(sizeof(*info), GFP_KERNEL);
445         if (info == NULL) {
446                 PRINT_ERROR("Can't alloc info (size %d)", sizeof(*info));
447                 err = -ENOMEM;
448                 goto out;
449         }
450
451         rc = copy_from_user(info, ptr, sizeof(*info));
452         if (rc != 0) {
453                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
454                 err = -EFAULT;
455                 goto out_free;
456         }
457
458         info->initiator_name[sizeof(info->initiator_name)-1] = '\0';
459 #ifdef CONFIG_SCST_PROC
460         info->user_name[sizeof(info->user_name)-1] = '\0';
461 #endif
462
463         target = target_lookup_by_id(info->tid);
464         if (target == NULL) {
465                 PRINT_ERROR("Target %d not found", info->tid);
466                 err = -ENOENT;
467                 goto out_free;
468         }
469
470         mutex_lock(&target->target_mutex);
471         err = __del_session(target, info->sid);
472         mutex_unlock(&target->target_mutex);
473
474 out_free:
475         kfree(info);
476
477 out:
478         TRACE_EXIT_RES(err);
479         return err;
480 }
481
482 /* target_mgmt_mutex supposed to be locked */
483 static int iscsi_params_config(void __user *ptr, int set)
484 {
485         int err, rc;
486         struct iscsi_kern_params_info info;
487         struct iscsi_target *target;
488
489         TRACE_ENTRY();
490
491         rc = copy_from_user(&info, ptr, sizeof(info));
492         if (rc != 0) {
493                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
494                 err = -EFAULT;
495                 goto out;
496         }
497
498         target = target_lookup_by_id(info.tid);
499         if (target == NULL) {
500                 PRINT_ERROR("Target %d not found", info.tid);
501                 err = -ENOENT;
502                 goto out;
503         }
504
505         mutex_lock(&target->target_mutex);
506         err = iscsi_params_set(target, &info, set);
507         mutex_unlock(&target->target_mutex);
508
509         if (err < 0)
510                 goto out;
511
512         if (!set) {
513                 rc = copy_to_user(ptr, &info, sizeof(info));
514                 if (rc != 0) {
515                         PRINT_ERROR("Failed to copy to user %d bytes", rc);
516                         err = -EFAULT;
517                         goto out;
518                 }
519         }
520
521 out:
522         TRACE_EXIT_RES(err);
523         return err;
524 }
525
526 #ifndef CONFIG_SCST_PROC
527
528 /* target_mgmt_mutex supposed to be locked */
529 static int mgmt_cmd_callback(void __user *ptr)
530 {
531         int err = 0, rc;
532         struct iscsi_kern_mgmt_cmd_res_info cinfo;
533         struct scst_sysfs_user_info *info;
534
535         TRACE_ENTRY();
536
537         rc = copy_from_user(&cinfo, ptr, sizeof(cinfo));
538         if (rc != 0) {
539                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
540                 err = -EFAULT;
541                 goto out;
542         }
543
544         cinfo.value[sizeof(cinfo.value)-1] = '\0';
545
546         info = scst_sysfs_user_get_info(cinfo.cookie);
547         TRACE_DBG("cookie %u, info %p, result %d", cinfo.cookie, info,
548                 cinfo.result);
549         if (info == NULL) {
550                 err = -EINVAL;
551                 goto out;
552         }
553
554         info->info_status = 0;
555
556         if (cinfo.result != 0) {
557                 info->info_status = cinfo.result;
558                 goto out_complete;
559         }
560
561         switch (cinfo.req_cmd) {
562         case E_ENABLE_TARGET:
563         case E_DISABLE_TARGET:
564         {
565                 struct iscsi_target *target;
566
567                 target = target_lookup_by_id(cinfo.tid);
568                 if (target == NULL) {
569                         PRINT_ERROR("Target %d not found", cinfo.tid);
570                         err = -ENOENT;
571                         goto out_status;
572                 }
573
574                 target->tgt_enabled = (cinfo.req_cmd == E_ENABLE_TARGET) ? 1 : 0;
575                 break;
576         }
577
578         case E_GET_ATTR_VALUE:
579                 info->data = kstrdup(cinfo.value, GFP_KERNEL);
580                 if (info->data == NULL) {
581                         PRINT_ERROR("Can't dublicate value %s", cinfo.value);
582                         info->info_status = -ENOMEM;
583                         goto out_complete;
584                 }
585                 break;
586         }
587
588 out_complete:
589         complete(&info->info_completion);
590
591 out:
592         TRACE_EXIT_RES(err);
593         return err;
594
595 out_status:
596         info->info_status = err;
597         goto out_complete;
598 }
599
600 static ssize_t iscsi_attr_show(struct kobject *kobj,
601         struct kobj_attribute *attr, char *buf)
602 {
603         int pos;
604         struct iscsi_attr *tgt_attr;
605         void *value;
606
607         TRACE_ENTRY();
608
609         tgt_attr = container_of(attr, struct iscsi_attr, attr);
610
611         pos = iscsi_sysfs_send_event(
612                 (tgt_attr->target != NULL) ? tgt_attr->target->tid : 0,
613                 E_GET_ATTR_VALUE, tgt_attr->name, NULL, &value);
614
615         if (pos != 0)
616                 goto out;
617
618         pos = scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, "%s\n", (char *)value);
619
620         kfree(value);
621
622 out:
623         TRACE_EXIT_RES(pos);
624         return pos;
625 }
626
627 static ssize_t iscsi_attr_store(struct kobject *kobj,
628         struct kobj_attribute *attr, const char *buf, size_t count)
629 {
630         int res;
631         char *buffer;
632         struct iscsi_attr *tgt_attr;
633
634         TRACE_ENTRY();
635
636         buffer = kzalloc(count+1, GFP_KERNEL);
637         if (buffer == NULL) {
638                 res = -ENOMEM;
639                 goto out;
640         }
641
642         memcpy(buffer, buf, count);
643         buffer[count] = '\0';
644
645         tgt_attr = container_of(attr, struct iscsi_attr, attr);
646
647         res = iscsi_sysfs_send_event(
648                 (tgt_attr->target != NULL) ? tgt_attr->target->tid : 0,
649                 E_SET_ATTR_VALUE, tgt_attr->name, buffer, NULL);
650
651         kfree(buffer);
652
653         if (res == 0)
654                 res = count;
655
656 out:
657         TRACE_EXIT_RES(res);
658         return res;
659 }
660
661 /*
662  * target_mgmt_mutex supposed to be locked. If target != 0, target_mutex
663  * supposed to be locked as well.
664  */
665 int iscsi_add_attr(struct iscsi_target *target,
666         const struct iscsi_kern_attr *attr_info)
667 {
668         int res = 0;
669         struct iscsi_attr *tgt_attr;
670         struct list_head *attrs_list;
671         const char *name;
672
673         TRACE_ENTRY();
674
675         if (target != NULL) {
676                 attrs_list = &target->attrs_list;
677                 name = target->name;
678         } else {
679                 attrs_list = &iscsi_attrs_list;
680                 name = "global";
681         }
682
683         list_for_each_entry(tgt_attr, attrs_list, attrs_list_entry) {
684                 if (strncmp(tgt_attr->name, attr_info->name,
685                                 sizeof(tgt_attr->name) == 0)) {
686                         PRINT_ERROR("Attribute %s for %s already exist",
687                                 attr_info->name, name);
688                         res = -EEXIST;
689                         goto out;
690                 }
691         }
692
693         TRACE_DBG("Adding %s's attr %s with mode %x", name,
694                 attr_info->name, attr_info->mode);
695
696         tgt_attr = kzalloc(sizeof(*tgt_attr), GFP_KERNEL);
697         if (tgt_attr == NULL) {
698                 PRINT_ERROR("Unable to allocate user (size %d)",
699                         sizeof(*tgt_attr));
700                 res = -ENOMEM;
701                 goto out;
702         }
703
704         tgt_attr->target = target;
705
706         tgt_attr->name = kstrdup(attr_info->name, GFP_KERNEL);
707         if (tgt_attr->name == NULL) {
708                 PRINT_ERROR("Unable to allocate attr %s name/value (target %s)",
709                         attr_info->name, name);
710                 res = -ENOMEM;
711                 goto out_free;
712         }
713
714         list_add(&tgt_attr->attrs_list_entry, attrs_list);
715
716         tgt_attr->attr.attr.name = tgt_attr->name;
717         tgt_attr->attr.attr.owner = THIS_MODULE;
718         tgt_attr->attr.attr.mode = attr_info->mode & (S_IRUGO | S_IWUGO);
719         tgt_attr->attr.show = iscsi_attr_show;
720         tgt_attr->attr.store = iscsi_attr_store;
721
722         res = sysfs_create_file(
723                 (target != NULL) ? scst_sysfs_get_tgt_kobj(target->scst_tgt) :
724                                 scst_sysfs_get_tgtt_kobj(&iscsi_template),
725                 &tgt_attr->attr.attr);
726         if (res != 0) {
727                 PRINT_ERROR("Unable to create file '%s' for target '%s'",
728                         tgt_attr->attr.attr.name, name);
729                 goto out_del;
730         }
731
732 out:
733         TRACE_EXIT_RES(res);
734         return res;
735
736 out_del:
737         list_del(&tgt_attr->attrs_list_entry);
738
739 out_free:
740         kfree(tgt_attr->name);
741         kfree(tgt_attr);
742         goto out;
743 }
744
745 void __iscsi_del_attr(struct iscsi_target *target,
746         struct iscsi_attr *tgt_attr)
747 {
748         TRACE_ENTRY();
749
750         TRACE_DBG("Deleting %s's attr %s",
751                 (target != NULL) ? target->name : "global", tgt_attr->name);
752
753         list_del(&tgt_attr->attrs_list_entry);
754
755         sysfs_remove_file((target != NULL) ?
756                         scst_sysfs_get_tgt_kobj(target->scst_tgt) :
757                         scst_sysfs_get_tgtt_kobj(&iscsi_template),
758                 &tgt_attr->attr.attr);
759
760         kfree(tgt_attr->name);
761         kfree(tgt_attr);
762
763         TRACE_EXIT();
764         return;
765 }
766
767 /*
768  * target_mgmt_mutex supposed to be locked. If target != 0, target_mutex
769  * supposed to be locked as well.
770  */
771 static int iscsi_del_attr(struct iscsi_target *target,
772         const char *attr_name)
773 {
774         int res = 0;
775         struct iscsi_attr *tgt_attr, *a;
776         struct list_head *attrs_list;
777
778         TRACE_ENTRY();
779
780         if (target != NULL)
781                 attrs_list = &target->attrs_list;
782         else
783                 attrs_list = &iscsi_attrs_list;
784
785         tgt_attr = NULL;
786         list_for_each_entry(a, attrs_list, attrs_list_entry) {
787                 if (strncmp(a->name, attr_name, sizeof(a->name)) == 0) {
788                         tgt_attr = a;
789                         break;
790                 }
791         }
792
793         if (tgt_attr == NULL) {
794                 PRINT_ERROR("attr %s not found (target %s)", attr_name,
795                         (target != NULL) ? target->name : "global");
796                 res = -ENOENT;
797                 goto out;
798         }
799
800         __iscsi_del_attr(target, tgt_attr);
801
802 out:
803         TRACE_EXIT_RES(res);
804         return res;
805 }
806
807 /* target_mgmt_mutex supposed to be locked */
808 static int iscsi_attr_cmd(void __user *ptr, unsigned int cmd)
809 {
810         int rc, err = 0;
811         struct iscsi_kern_attr_info info;
812         struct iscsi_target *target;
813         struct scst_sysfs_user_info *i = NULL;
814
815         TRACE_ENTRY();
816
817         rc = copy_from_user(&info, ptr, sizeof(info));
818         if (rc != 0) {
819                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
820                 err = -EFAULT;
821                 goto out;
822         }
823
824         info.attr.name[sizeof(info.attr.name)-1] = '\0';
825
826         if (info.cookie != 0) {
827                 i = scst_sysfs_user_get_info(info.cookie);
828                 TRACE_DBG("cookie %u, uinfo %p", info.cookie, i);
829                 if (i == NULL) {
830                         err = -EINVAL;
831                         goto out;
832                 }
833         }
834
835         target = target_lookup_by_id(info.tid);
836
837         if (target != NULL)
838                 mutex_lock(&target->target_mutex);
839
840         switch (cmd) {
841         case ISCSI_ATTR_ADD:
842                 err = iscsi_add_attr(target, &info.attr);
843                 break;
844         case ISCSI_ATTR_DEL:
845                 err = iscsi_del_attr(target, info.attr.name);
846                 break;
847         default:
848                 sBUG();
849         }
850
851         if (target != NULL)
852                 mutex_unlock(&target->target_mutex);
853
854         if (i != NULL) {
855                 i->info_status = err;
856                 complete(&i->info_completion);
857         }
858
859 out:
860         TRACE_EXIT_RES(err);
861         return err;
862 }
863
864 #endif /* CONFIG_SCST_PROC */
865
866 /* target_mgmt_mutex supposed to be locked */
867 static int add_target(void __user *ptr)
868 {
869         int err, rc;
870         struct iscsi_kern_target_info *info;
871 #ifndef CONFIG_SCST_PROC
872         struct scst_sysfs_user_info *uinfo;
873 #endif
874
875         TRACE_ENTRY();
876
877         info = kzalloc(sizeof(*info), GFP_KERNEL);
878         if (info == NULL) {
879                 PRINT_ERROR("Can't alloc info (size %d)", sizeof(*info));
880                 err = -ENOMEM;
881                 goto out;
882         }
883
884         rc = copy_from_user(info, ptr, sizeof(*info));
885         if (rc != 0) {
886                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
887                 err = -EFAULT;
888                 goto out_free;
889         }
890
891         if (target_lookup_by_id(info->tid) != NULL) {
892                 PRINT_ERROR("Target %u already exist!", info->tid);
893                 err = -EEXIST;
894                 goto out_free;
895         }
896
897         info->name[sizeof(info->name)-1] = '\0';
898
899 #ifndef CONFIG_SCST_PROC
900         if (info->cookie != 0) {
901                 uinfo = scst_sysfs_user_get_info(info->cookie);
902                 TRACE_DBG("cookie %u, uinfo %p", info->cookie, uinfo);
903                 if (uinfo == NULL) {
904                         err = -EINVAL;
905                         goto out_free;
906                 }
907         } else
908                 uinfo = NULL;
909 #endif
910
911         err = __add_target(info);
912
913 #ifndef CONFIG_SCST_PROC
914         if (uinfo != NULL) {
915                 uinfo->info_status = err;
916                 complete(&uinfo->info_completion);
917         }
918 #endif
919
920 out_free:
921         kfree(info);
922
923 out:
924         TRACE_EXIT_RES(err);
925         return err;
926 }
927
928 /* target_mgmt_mutex supposed to be locked */
929 static int del_target(void __user *ptr)
930 {
931         int err, rc;
932         struct iscsi_kern_target_info info;
933 #ifndef CONFIG_SCST_PROC
934         struct scst_sysfs_user_info *uinfo;
935 #endif
936
937         TRACE_ENTRY();
938
939         rc = copy_from_user(&info, ptr, sizeof(info));
940         if (rc != 0) {
941                 PRINT_ERROR("Failed to copy %d user's bytes", rc);
942                 err = -EFAULT;
943                 goto out;
944         }
945
946         info.name[sizeof(info.name)-1] = '\0';
947
948 #ifndef CONFIG_SCST_PROC
949         if (info.cookie != 0) {
950                 uinfo = scst_sysfs_user_get_info(info.cookie);
951                 TRACE_DBG("cookie %u, uinfo %p", info.cookie, uinfo);
952                 if (uinfo == NULL) {
953                         err = -EINVAL;
954                         goto out;
955                 }
956         } else
957                 uinfo = NULL;
958 #endif
959
960         err = __del_target(info.tid);
961
962 #ifndef CONFIG_SCST_PROC
963         if (uinfo != NULL) {
964                 uinfo->info_status = err;
965                 complete(&uinfo->info_completion);
966         }
967 #endif
968
969 out:
970         TRACE_EXIT_RES(err);
971         return err;
972 }
973
974 static int iscsi_register(void __user *arg)
975 {
976         struct iscsi_kern_register_info reg;
977         char ver[sizeof(ISCSI_SCST_INTERFACE_VERSION)+1];
978         int res, rc;
979
980         TRACE_ENTRY();
981
982         rc = copy_from_user(&reg, arg, sizeof(reg));
983         if (rc != 0) {
984                 PRINT_ERROR("%s", "Unable to get register info");
985                 res = -EFAULT;
986                 goto out;
987         }
988
989         rc = copy_from_user(ver, (void __user *)(unsigned long)reg.version,
990                                 sizeof(ver));
991         if (rc != 0) {
992                 PRINT_ERROR("%s", "Unable to get version string");
993                 res = -EFAULT;
994                 goto out;
995         }
996         ver[sizeof(ver)-1] = '\0';
997
998         if (strcmp(ver, ISCSI_SCST_INTERFACE_VERSION) != 0) {
999                 PRINT_ERROR("Incorrect version of user space %s (expected %s)",
1000                         ver, ISCSI_SCST_INTERFACE_VERSION);
1001                 res = -EINVAL;
1002                 goto out;
1003         }
1004
1005         memset(&reg, 0, sizeof(reg));
1006         reg.max_data_seg_len = ISCSI_CONN_IOV_MAX << PAGE_SHIFT;
1007
1008         res = 0;
1009
1010         rc = copy_to_user(arg, &reg, sizeof(reg));
1011         if (rc != 0) {
1012                 PRINT_ERROR("Failed to copy to user %d bytes", rc);
1013                 res = -EFAULT;
1014                 goto out;
1015         }
1016
1017 out:
1018         TRACE_EXIT_RES(res);
1019         return res;
1020 }
1021
1022 static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1023 {
1024         long err;
1025
1026         TRACE_ENTRY();
1027
1028         if (cmd == REGISTER_USERD) {
1029                 err = iscsi_register((void __user *)arg);
1030                 goto out;
1031         }
1032
1033         err = mutex_lock_interruptible(&target_mgmt_mutex);
1034         if (err < 0)
1035                 goto out;
1036
1037         switch (cmd) {
1038         case ADD_TARGET:
1039                 err = add_target((void __user *)arg);
1040                 break;
1041
1042         case DEL_TARGET:
1043                 err = del_target((void __user *)arg);
1044                 break;
1045
1046 #ifndef CONFIG_SCST_PROC
1047         case ISCSI_ATTR_ADD:
1048         case ISCSI_ATTR_DEL:
1049                 err = iscsi_attr_cmd((void __user *)arg, cmd);
1050                 break;
1051
1052         case MGMT_CMD_CALLBACK:
1053                 err = mgmt_cmd_callback((void __user *)arg);
1054                 break;
1055 #endif
1056
1057         case ADD_SESSION:
1058                 err = add_session((void __user *)arg);
1059                 break;
1060
1061         case DEL_SESSION:
1062                 err = del_session((void __user *)arg);
1063                 break;
1064
1065         case ISCSI_PARAM_SET:
1066                 err = iscsi_params_config((void __user *)arg, 1);
1067                 break;
1068
1069         case ISCSI_PARAM_GET:
1070                 err = iscsi_params_config((void __user *)arg, 0);
1071                 break;
1072
1073         case ADD_CONN:
1074                 err = add_conn((void __user *)arg);
1075                 break;
1076
1077         case DEL_CONN:
1078                 err = del_conn((void __user *)arg);
1079                 break;
1080
1081         default:
1082                 PRINT_ERROR("Invalid ioctl cmd %x", cmd);
1083                 err = -EINVAL;
1084                 goto out_unlock;
1085         }
1086
1087 out_unlock:
1088         mutex_unlock(&target_mgmt_mutex);
1089
1090 out:
1091         TRACE_EXIT_RES(err);
1092         return err;
1093 }
1094
1095 int open(struct inode *inode, struct file *file)
1096 {
1097         bool already;
1098
1099         mutex_lock(&target_mgmt_mutex);
1100         already = (ctr_open_state != ISCSI_CTR_OPEN_STATE_CLOSED);
1101         if (!already)
1102                 ctr_open_state = ISCSI_CTR_OPEN_STATE_OPEN;
1103         mutex_unlock(&target_mgmt_mutex);
1104
1105         if (already) {
1106                 PRINT_WARNING("%s", "Attempt to second open the control "
1107                         "device!");
1108                 return -EBUSY;
1109         } else
1110                 return 0;
1111 }
1112
1113 static int release(struct inode *inode, struct file *filp)
1114 {
1115 #ifndef CONFIG_SCST_PROC
1116         struct iscsi_attr *attr, *t;
1117 #endif
1118
1119         TRACE(TRACE_MGMT, "%s", "Releasing allocated resources");
1120
1121         mutex_lock(&target_mgmt_mutex);
1122         ctr_open_state = ISCSI_CTR_OPEN_STATE_CLOSING;
1123         mutex_unlock(&target_mgmt_mutex);
1124
1125         target_del_all();
1126
1127         mutex_lock(&target_mgmt_mutex);
1128
1129 #ifndef CONFIG_SCST_PROC
1130         list_for_each_entry_safe(attr, t, &iscsi_attrs_list,
1131                                         attrs_list_entry) {
1132                 __iscsi_del_attr(NULL, attr);
1133         }
1134 #endif
1135
1136         ctr_open_state = ISCSI_CTR_OPEN_STATE_CLOSED;
1137
1138         mutex_unlock(&target_mgmt_mutex);
1139
1140         return 0;
1141 }
1142
1143 const struct file_operations ctr_fops = {
1144         .owner          = THIS_MODULE,
1145         .unlocked_ioctl = ioctl,
1146         .compat_ioctl   = ioctl,
1147         .open           = open,
1148         .release        = release,
1149 };
1150
1151 #ifdef CONFIG_SCST_DEBUG
1152 static void iscsi_dump_char(int ch, unsigned char *text, int *pos)
1153 {
1154         int i = *pos;
1155
1156         if (ch < 0) {
1157                 while ((i % 16) != 0) {
1158                         printk(KERN_CONT "   ");
1159                         text[i] = ' ';
1160                         i++;
1161                         if ((i % 16) == 0)
1162                                 printk(KERN_CONT " | %.16s |\n", text);
1163                         else if ((i % 4) == 0)
1164                                 printk(KERN_CONT " |");
1165                 }
1166                 i = 0;
1167                 goto out;
1168         }
1169
1170         text[i] = (ch < 0x20 || (ch >= 0x80 && ch <= 0xa0)) ? ' ' : ch;
1171         printk(KERN_CONT " %02x", ch);
1172         i++;
1173         if ((i % 16) == 0) {
1174                 printk(KERN_CONT " | %.16s |\n", text);
1175                 i = 0;
1176         } else if ((i % 4) == 0)
1177                 printk(KERN_CONT " |");
1178
1179 out:
1180         *pos = i;
1181         return;
1182 }
1183
1184 void iscsi_dump_pdu(struct iscsi_pdu *pdu)
1185 {
1186         unsigned char text[16];
1187         int pos = 0;
1188
1189         if (trace_flag & TRACE_D_DUMP_PDU) {
1190                 unsigned char *buf;
1191                 int i;
1192
1193                 buf = (void *)&pdu->bhs;
1194                 printk(KERN_DEBUG "BHS: (%p,%zd)\n", buf, sizeof(pdu->bhs));
1195                 for (i = 0; i < (int)sizeof(pdu->bhs); i++)
1196                         iscsi_dump_char(*buf++, text, &pos);
1197                 iscsi_dump_char(-1, text, &pos);
1198
1199                 buf = (void *)pdu->ahs;
1200                 printk(KERN_DEBUG "AHS: (%p,%d)\n", buf, pdu->ahssize);
1201                 for (i = 0; i < pdu->ahssize; i++)
1202                         iscsi_dump_char(*buf++, text, &pos);
1203                 iscsi_dump_char(-1, text, &pos);
1204
1205                 printk(KERN_DEBUG "Data: (%d)\n", pdu->datasize);
1206         }
1207 }
1208
1209 unsigned long iscsi_get_flow_ctrl_or_mgmt_dbg_log_flag(struct iscsi_cmnd *cmnd)
1210 {
1211         unsigned long flag;
1212
1213         if (cmnd->cmd_req != NULL)
1214                 cmnd = cmnd->cmd_req;
1215
1216         if (cmnd->scst_cmd == NULL)
1217                 flag = TRACE_MGMT_DEBUG;
1218         else {
1219                 int status = scst_cmd_get_status(cmnd->scst_cmd);
1220                 if ((status == SAM_STAT_TASK_SET_FULL) ||
1221                     (status == SAM_STAT_BUSY))
1222                         flag = TRACE_FLOW_CONTROL;
1223                 else
1224                         flag = TRACE_MGMT_DEBUG;
1225         }
1226         return flag;
1227 }
1228
1229 #endif /* CONFIG_SCST_DEBUG */