Patch from Alexey Obitotskiy <alexeyo1@open-e.com> with 2 fixes and cleanups implemen...
[mirror/scst/.git] / scst / src / scst_sysfs.c
1 /*
2  *  scst_sysfs.c
3  *
4  *  Copyright (C) 2009 Daniel Henrique Debonzi <debonzi@linux.vnet.ibm.com>
5  *  Copyright (C) 2009 Vladislav Bolkhovitin <vst@vlnb.net>
6  *  Copyright (C) 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/kobject.h>
20 #include <linux/string.h>
21 #include <linux/sysfs.h>
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/ctype.h>
25
26 #include "scst.h"
27 #include "scst_priv.h"
28 #include "scst_mem.h"
29
30 static DEFINE_MUTEX(scst_sysfs_mutex);
31
32 static DECLARE_COMPLETION(scst_sysfs_root_release_completion);
33
34 static struct kobject scst_sysfs_root_kobj;
35 static struct kobject *scst_targets_kobj;
36 static struct kobject *scst_devices_kobj;
37 static struct kobject *scst_sgv_kobj;
38 static struct kobject *scst_handlers_kobj;
39
40 struct sysfs_ops scst_sysfs_ops;
41 EXPORT_SYMBOL(scst_sysfs_ops);
42
43 static const char *scst_dev_handler_types[] = {
44     "Direct-access device (e.g., magnetic disk)",
45     "Sequential-access device (e.g., magnetic tape)",
46     "Printer device",
47     "Processor device",
48     "Write-once device (e.g., some optical disks)",
49     "CD-ROM device",
50     "Scanner device (obsolete)",
51     "Optical memory device (e.g., some optical disks)",
52     "Medium changer device (e.g., jukeboxes)",
53     "Communications device (obsolete)",
54     "Defined by ASC IT8 (Graphic arts pre-press devices)",
55     "Defined by ASC IT8 (Graphic arts pre-press devices)",
56     "Storage array controller device (e.g., RAID)",
57     "Enclosure services device",
58     "Simplified direct-access device (e.g., magnetic disk)",
59     "Optical card reader/writer device"
60 };
61
62 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
63
64 static DEFINE_MUTEX(scst_log_mutex);
65
66 static struct scst_trace_log scst_trace_tbl[] = {
67     { TRACE_OUT_OF_MEM,         "out_of_mem" },
68     { TRACE_MINOR,              "minor" },
69     { TRACE_SG_OP,              "sg" },
70     { TRACE_MEMORY,             "mem" },
71     { TRACE_BUFF,               "buff" },
72 #ifndef GENERATING_UPSTREAM_PATCH
73     { TRACE_ENTRYEXIT,          "entryexit" },
74 #endif
75     { TRACE_PID,                "pid" },
76     { TRACE_LINE,               "line" },
77     { TRACE_FUNCTION,           "function" },
78     { TRACE_DEBUG,              "debug" },
79     { TRACE_SPECIAL,            "special" },
80     { TRACE_SCSI,               "scsi" },
81     { TRACE_MGMT,               "mgmt" },
82     { TRACE_MGMT_MINOR,         "mgmt_minor" },
83     { TRACE_MGMT_DEBUG,         "mgmt_dbg" },
84     { TRACE_FLOW_CONTROL,       "flow_control" },
85     { 0,                        NULL }
86 };
87
88 static struct scst_trace_log scst_local_trace_tbl[] = {
89     { TRACE_RTRY,               "retry" },
90     { TRACE_SCSI_SERIALIZING,   "scsi_serializing" },
91     { TRACE_RCV_BOT,            "recv_bot" },
92     { TRACE_SND_BOT,            "send_bot" },
93     { TRACE_RCV_TOP,            "recv_top" },
94     { TRACE_SND_TOP,            "send_top" },
95     { 0,                        NULL }
96 };
97
98 static ssize_t scst_trace_level_show(const struct scst_trace_log *local_tbl,
99         unsigned long log_level, char *buf, const char *help);
100 static int scst_write_trace(const char *buf, size_t length,
101         unsigned long *log_level, unsigned long default_level,
102         const char *name, const struct scst_trace_log *tbl);
103
104 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
105
106 static ssize_t scst_luns_mgmt_show(struct kobject *kobj,
107                                    struct kobj_attribute *attr,
108                                    char *buf);
109 static ssize_t scst_luns_mgmt_store(struct kobject *kobj,
110                                     struct kobj_attribute *attr,
111                                     const char *buf, size_t count);
112 static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj,
113                                    struct kobj_attribute *attr,
114                                    char *buf);
115 static ssize_t scst_ini_group_mgmt_store(struct kobject *kobj,
116                                     struct kobj_attribute *attr,
117                                     const char *buf, size_t count);
118 static ssize_t scst_acg_luns_mgmt_show(struct kobject *kobj,
119                                    struct kobj_attribute *attr,
120                                    char *buf);
121 static ssize_t scst_acg_luns_mgmt_store(struct kobject *kobj,
122                                     struct kobj_attribute *attr,
123                                     const char *buf, size_t count);
124 static ssize_t scst_acg_ini_mgmt_show(struct kobject *kobj,
125                                    struct kobj_attribute *attr,
126                                    char *buf);
127 static ssize_t scst_acg_ini_mgmt_store(struct kobject *kobj,
128                                     struct kobj_attribute *attr,
129                                     const char *buf, size_t count);
130 static ssize_t scst_acn_file_show(struct kobject *kobj,
131         struct kobj_attribute *attr, char *buf);
132
133 static void scst_sysfs_release(struct kobject *kobj)
134 {
135         kfree(kobj);
136 }
137
138 /*
139  * Target Template
140  */
141
142 static void scst_tgtt_release(struct kobject *kobj)
143 {
144         struct scst_tgt_template *tgtt;
145
146         TRACE_ENTRY();
147
148         tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
149
150         complete_all(&tgtt->tgtt_kobj_release_cmpl);
151
152         scst_tgtt_cleanup(tgtt);
153
154         TRACE_EXIT();
155         return;
156 }
157
158 static struct kobj_type tgtt_ktype = {
159         .sysfs_ops = &scst_sysfs_ops,
160         .release = scst_tgtt_release,
161 };
162
163 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
164
165 static ssize_t scst_tgtt_trace_level_show(struct kobject *kobj,
166         struct kobj_attribute *attr, char *buf)
167 {
168         struct scst_tgt_template *tgtt;
169
170         tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
171
172         return scst_trace_level_show(tgtt->trace_tbl,
173                 tgtt->trace_flags ? *tgtt->trace_flags : 0, buf,
174                 tgtt->trace_tbl_help);
175 }
176
177 static ssize_t scst_tgtt_trace_level_store(struct kobject *kobj,
178         struct kobj_attribute *attr, const char *buf, size_t count)
179 {
180         int res;
181         struct scst_tgt_template *tgtt;
182
183         TRACE_ENTRY();
184
185         tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
186
187         if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
188                 res = -EINTR;
189                 goto out;
190         }
191
192         res = scst_write_trace(buf, count, tgtt->trace_flags,
193                 tgtt->default_trace_flags, tgtt->name, tgtt->trace_tbl);
194
195         mutex_unlock(&scst_log_mutex);
196
197 out:
198         TRACE_EXIT_RES(res);
199         return res;
200 }
201
202 static struct kobj_attribute tgtt_trace_attr =
203         __ATTR(trace_level, S_IRUGO | S_IWUSR,
204                scst_tgtt_trace_level_show, scst_tgtt_trace_level_store);
205
206 #endif /* #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
207
208 int scst_create_tgtt_sysfs(struct scst_tgt_template *tgtt)
209 {
210         int retval = 0;
211         const struct attribute **pattr;
212
213         TRACE_ENTRY();
214
215         init_completion(&tgtt->tgtt_kobj_release_cmpl);
216
217         tgtt->tgtt_kobj_initialized = 1;
218
219         retval = kobject_init_and_add(&tgtt->tgtt_kobj, &tgtt_ktype,
220                         scst_targets_kobj, tgtt->name);
221         if (retval != 0) {
222                 PRINT_ERROR("Can't add tgtt %s to sysfs", tgtt->name);
223                 goto out;
224         }
225
226         /*
227          * In case of errors there's no need for additional cleanup, because
228          * it will be done by the _put function() called by the caller.
229          */
230
231         pattr = tgtt->tgtt_attrs;
232         if (pattr != NULL) {
233                 while (*pattr != NULL) {
234                         TRACE_DBG("Creating attr %s for target driver %s",
235                                 (*pattr)->name, tgtt->name);
236                         retval = sysfs_create_file(&tgtt->tgtt_kobj, *pattr);
237                         if (retval != 0) {
238                                 PRINT_ERROR("Can't add attr %s for target "
239                                         "driver %s", (*pattr)->name,
240                                         tgtt->name);
241                                 goto out;
242                         }
243                         pattr++;
244                 }
245         }
246
247 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
248         if (tgtt->trace_flags != NULL) {
249                 retval = sysfs_create_file(&tgtt->tgtt_kobj,
250                                 &tgtt_trace_attr.attr);
251                 if (retval != 0) {
252                         PRINT_ERROR("Can't add trace_flag for target "
253                                 "driver %s", tgtt->name);
254                         goto out;
255                 }
256         }
257 #endif
258
259 out:
260         TRACE_EXIT_RES(retval);
261         return retval;
262 }
263
264 void scst_tgtt_sysfs_put(struct scst_tgt_template *tgtt)
265 {
266         TRACE_ENTRY();
267
268         if (tgtt->tgtt_kobj_initialized) {
269                 int rc;
270
271                 kobject_del(&tgtt->tgtt_kobj);
272                 kobject_put(&tgtt->tgtt_kobj);
273
274                 rc = wait_for_completion_timeout(&tgtt->tgtt_kobj_release_cmpl, HZ);
275                 if (rc == 0) {
276                         PRINT_INFO("Waiting for releasing sysfs entry "
277                                 "for target template %s...", tgtt->name);
278                         wait_for_completion(&tgtt->tgtt_kobj_release_cmpl);
279                         PRINT_INFO("Done waiting for releasing sysfs "
280                                 "entry for target template %s", tgtt->name);
281                 }
282         } else
283                 scst_tgtt_cleanup(tgtt);
284
285         TRACE_EXIT();
286         return;
287 }
288
289 /*
290  * Target directory implementation
291  */
292
293 static void scst_tgt_release(struct kobject *kobj)
294 {
295         struct scst_tgt *tgt;
296
297         TRACE_ENTRY();
298
299         tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
300
301         /* Let's make lockdep happy */
302         up_write(&tgt->tgt_attr_rwsem);
303
304         scst_free_tgt(tgt);
305
306         TRACE_EXIT();
307         return;
308 }
309
310 static ssize_t scst_tgt_attr_show(struct kobject *kobj, struct attribute *attr,
311         char *buf)
312 {
313         int res;
314         struct kobj_attribute *kobj_attr;
315         struct scst_tgt *tgt;
316
317         tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
318
319         if (down_read_trylock(&tgt->tgt_attr_rwsem) == 0) {
320                 res = -ENOENT;
321                 goto out;
322         }
323
324         kobj_attr = container_of(attr, struct kobj_attribute, attr);
325
326         res = kobj_attr->show(kobj, kobj_attr, buf);
327
328         up_read(&tgt->tgt_attr_rwsem);
329
330 out:
331         return res;
332 }
333
334 static ssize_t scst_tgt_attr_store(struct kobject *kobj,
335         struct attribute *attr, const char *buf, size_t count)
336 {
337         int res;
338         struct kobj_attribute *kobj_attr;
339         struct scst_tgt *tgt;
340
341         tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
342
343         if (down_read_trylock(&tgt->tgt_attr_rwsem) == 0) {
344                 res = -ENOENT;
345                 goto out;
346         }
347
348         kobj_attr = container_of(attr, struct kobj_attribute, attr);
349
350         res = kobj_attr->store(kobj, kobj_attr, buf, count);
351
352         up_read(&tgt->tgt_attr_rwsem);
353
354 out:
355         return res;
356 }
357
358 static struct sysfs_ops scst_tgt_sysfs_ops = {
359         .show = scst_tgt_attr_show,
360         .store = scst_tgt_attr_store,
361 };
362
363 static struct kobj_type tgt_ktype = {
364         .sysfs_ops = &scst_tgt_sysfs_ops,
365         .release = scst_tgt_release,
366 };
367
368 static void scst_acg_release(struct kobject *kobj)
369 {
370         struct scst_acg *acg;
371
372         TRACE_ENTRY();
373
374         acg = container_of(kobj, struct scst_acg, acg_kobj);
375
376         scst_destroy_acg(acg);
377
378         TRACE_EXIT();
379         return;
380 }
381
382 static struct kobj_type acg_ktype = {
383         .sysfs_ops = &scst_sysfs_ops,
384         .release = scst_acg_release,
385 };
386
387 static struct kobj_attribute scst_luns_mgmt =
388         __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_luns_mgmt_show,
389                scst_luns_mgmt_store);
390
391 static struct kobj_attribute scst_acg_luns_mgmt =
392         __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_acg_luns_mgmt_show,
393                scst_acg_luns_mgmt_store);
394
395 static struct kobj_attribute scst_acg_ini_mgmt =
396         __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_acg_ini_mgmt_show,
397                scst_acg_ini_mgmt_store);
398
399 static struct kobj_attribute scst_ini_group_mgmt =
400         __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_ini_group_mgmt_show,
401                scst_ini_group_mgmt_store);
402
403 static ssize_t scst_tgt_enable_show(struct kobject *kobj,
404         struct kobj_attribute *attr, char *buf)
405 {
406         struct scst_tgt *tgt;
407         int res;
408         bool enabled;
409
410         TRACE_ENTRY();
411
412         tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
413
414         enabled = tgt->tgtt->is_tgt_enabled(tgt);
415
416         res = sprintf(buf, "%d\n", enabled ? 1 : 0);
417
418         TRACE_EXIT_RES(res);
419         return res;
420 }
421
422 static ssize_t scst_tgt_enable_store(struct kobject *kobj,
423         struct kobj_attribute *attr, const char *buf, size_t count)
424 {
425         int res;
426         struct scst_tgt *tgt;
427
428         TRACE_ENTRY();
429
430         if (buf == NULL)
431                 goto out_err;
432
433         tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
434
435         res = tgt->tgtt->enable_tgt(tgt, buf, count);
436
437 out:
438         TRACE_EXIT_RES(res);
439         return res;
440
441 out_err:
442         PRINT_ERROR("%s: Requested action not understood: %s", __func__, buf);
443         res = -EINVAL;
444         goto out;
445 }
446
447 static struct kobj_attribute tgt_enable_attr =
448         __ATTR(enabled, S_IRUGO | S_IWUSR,
449                scst_tgt_enable_show, scst_tgt_enable_store);
450
451 int scst_create_tgt_sysfs(struct scst_tgt *tgt)
452 {
453         int retval;
454         const struct attribute **pattr;
455
456         TRACE_ENTRY();
457
458         init_rwsem(&tgt->tgt_attr_rwsem);
459
460         tgt->tgt_kobj_initialized = 1;
461
462         retval = kobject_init_and_add(&tgt->tgt_kobj, &tgt_ktype,
463                         &tgt->tgtt->tgtt_kobj, tgt->tgt_name);
464         if (retval != 0) {
465                 PRINT_ERROR("Can't add tgt %s to sysfs", tgt->tgt_name);
466                 goto out;
467         }
468
469         /*
470          * In case of errors there's no need for additional cleanup, because
471          * it will be done by the _put function() called by the caller.
472          */
473
474         if ((tgt->tgtt->enable_tgt != NULL) &&
475             (tgt->tgtt->is_tgt_enabled != NULL)) {
476                 retval = sysfs_create_file(&tgt->tgt_kobj,
477                                 &tgt_enable_attr.attr);
478                 if (retval != 0) {
479                         PRINT_ERROR("Can't add attr %s to sysfs",
480                                 tgt_enable_attr.attr.name);
481                         goto out;
482                 }
483         }
484
485         tgt->tgt_sess_kobj = kobject_create_and_add("sessions", &tgt->tgt_kobj);
486         if (tgt->tgt_sess_kobj == NULL) {
487                 PRINT_ERROR("Can't create sess kobj for tgt %s", tgt->tgt_name);
488                 goto out_nomem;
489         }
490
491         tgt->tgt_luns_kobj = kobject_create_and_add("luns", &tgt->tgt_kobj);
492         if (tgt->tgt_luns_kobj == NULL) {
493                 PRINT_ERROR("Can't create luns kobj for tgt %s", tgt->tgt_name);
494                 goto out_nomem;
495         }
496
497         retval = sysfs_create_file(tgt->tgt_luns_kobj, &scst_luns_mgmt.attr);
498         if (retval != 0) {
499                 PRINT_ERROR("Can't add tgt attr %s for tgt %s",
500                         scst_luns_mgmt.attr.name, tgt->tgt_name);
501                 goto out;
502         }
503
504         tgt->tgt_ini_grp_kobj = kobject_create_and_add("ini_group",
505                                         &tgt->tgt_kobj);
506         if (tgt->tgt_ini_grp_kobj == NULL) {
507                 PRINT_ERROR("Can't create ini_grp kobj for tgt %s",
508                         tgt->tgt_name);
509                 goto out_nomem;
510         }
511
512         retval = sysfs_create_file(tgt->tgt_ini_grp_kobj,
513                 &scst_ini_group_mgmt.attr);
514         if (retval != 0) {
515                 PRINT_ERROR("Can't add tgt attr %s for tgt %s",
516                         scst_ini_group_mgmt.attr.name, tgt->tgt_name);
517                 goto out;
518         }
519
520         pattr = tgt->tgtt->tgt_attrs;
521         if (pattr != NULL) {
522                 while (*pattr != NULL) {
523                         TRACE_DBG("Creating attr %s for tgt %s", (*pattr)->name,
524                                 tgt->tgt_name);
525                         retval = sysfs_create_file(&tgt->tgt_kobj, *pattr);
526                         if (retval != 0) {
527                                 PRINT_ERROR("Can't add tgt attr %s for tgt %s",
528                                         (*pattr)->name, tgt->tgt_name);
529                                 goto out;
530                         }
531                         pattr++;
532                 }
533         }
534
535 out:
536         TRACE_EXIT_RES(retval);
537         return retval;
538
539 out_nomem:
540         retval = -ENOMEM;
541         goto out;
542 }
543
544 /*
545  * Must not be called under scst_mutex or there can be a deadlock with
546  * tgt_attr_rwsem
547  */
548 void scst_tgt_sysfs_prepare_put(struct scst_tgt *tgt)
549 {
550         if (tgt->tgt_kobj_initialized) {
551                 down_write(&tgt->tgt_attr_rwsem);
552                 tgt->tgt_kobj_put_prepared = 1;
553         }
554
555         return;
556 }
557
558 /*
559  * Must not be called under scst_mutex or there can be a deadlock with
560  * tgt_attr_rwsem
561  */
562 void scst_tgt_sysfs_put(struct scst_tgt *tgt)
563 {
564         if (tgt->tgt_kobj_initialized) {
565                 kobject_del(tgt->tgt_sess_kobj);
566                 kobject_put(tgt->tgt_sess_kobj);
567
568                 kobject_del(tgt->tgt_luns_kobj);
569                 kobject_put(tgt->tgt_luns_kobj);
570
571                 kobject_del(tgt->tgt_ini_grp_kobj);
572                 kobject_put(tgt->tgt_ini_grp_kobj);
573
574                 kobject_del(&tgt->tgt_kobj);
575
576                 if (!tgt->tgt_kobj_put_prepared)
577                         down_write(&tgt->tgt_attr_rwsem);
578                 kobject_put(&tgt->tgt_kobj);
579         } else
580                 scst_free_tgt(tgt);
581         return;
582 }
583
584 /*
585  * Devices directory implementation
586  */
587
588 ssize_t scst_device_sysfs_type_show(struct kobject *kobj,
589                             struct kobj_attribute *attr, char *buf)
590 {
591         int pos = 0;
592
593         struct scst_device *dev;
594
595         dev = container_of(kobj, struct scst_device, dev_kobj);
596
597         pos = sprintf(buf, "%d - %s\n", dev->type,
598                 (unsigned)dev->type > ARRAY_SIZE(scst_dev_handler_types) ?
599                       "unknown" : scst_dev_handler_types[dev->type]);
600
601         return pos;
602 }
603
604 static struct kobj_attribute device_type_attr =
605         __ATTR(type, S_IRUGO, scst_device_sysfs_type_show, NULL);
606
607 static struct attribute *scst_device_attrs[] = {
608         &device_type_attr.attr,
609         NULL,
610 };
611
612 static void scst_sysfs_device_release(struct kobject *kobj)
613 {
614         struct scst_device *dev;
615
616         TRACE_ENTRY();
617
618         dev = container_of(kobj, struct scst_device, dev_kobj);
619
620         /* Let's make lockdep happy */
621         up_write(&dev->dev_attr_rwsem);
622
623         scst_free_device(dev);
624
625         TRACE_EXIT();
626         return;
627 }
628
629 int scst_create_devt_dev_sysfs(struct scst_device *dev)
630 {
631         int retval = 0;
632         const struct attribute **pattr;
633
634         TRACE_ENTRY();
635
636         if (dev->handler == &scst_null_devtype)
637                 goto out;
638
639         sBUG_ON(!dev->handler->devt_kobj_initialized);
640
641         /*
642          * In case of errors there's no need for additional cleanup, because
643          * it will be done by the _put function() called by the caller.
644          */
645
646         retval = sysfs_create_link(&dev->dev_kobj,
647                         &dev->handler->devt_kobj, "handler");
648         if (retval != 0) {
649                 PRINT_ERROR("Can't create handler link for dev %s",
650                         dev->virt_name);
651                 goto out;
652         }
653
654         pattr = dev->handler->dev_attrs;
655         if (pattr != NULL) {
656                 while (*pattr != NULL) {
657                         retval = sysfs_create_file(&dev->dev_kobj, *pattr);
658                         if (retval != 0) {
659                                 PRINT_ERROR("Can't add dev attr %s for dev %s",
660                                         (*pattr)->name, dev->virt_name);
661                                 goto out;
662                         }
663                         pattr++;
664                 }
665         }
666
667 out:
668         TRACE_EXIT_RES(retval);
669         return retval;
670 }
671
672 void scst_devt_dev_sysfs_put(struct scst_device *dev)
673 {
674         const struct attribute **pattr;
675
676         TRACE_ENTRY();
677
678         if (dev->handler == &scst_null_devtype)
679                 goto out;
680
681         sBUG_ON(!dev->handler->devt_kobj_initialized);
682
683         pattr = dev->handler->dev_attrs;
684         if (pattr != NULL) {
685                 while (*pattr != NULL) {
686                         sysfs_remove_file(&dev->dev_kobj, *pattr);
687                         pattr++;
688                 }
689         }
690
691         sysfs_remove_link(&dev->dev_kobj, "handler");
692
693 out:
694         TRACE_EXIT();
695         return;
696 }
697
698 static ssize_t scst_dev_attr_show(struct kobject *kobj, struct attribute *attr,
699                          char *buf)
700 {
701         int res;
702         struct kobj_attribute *kobj_attr;
703         struct scst_device *dev;
704
705         dev = container_of(kobj, struct scst_device, dev_kobj);
706
707         if (down_read_trylock(&dev->dev_attr_rwsem) == 0) {
708                 res = -ENOENT;
709                 goto out;
710         }
711
712         kobj_attr = container_of(attr, struct kobj_attribute, attr);
713
714         res = kobj_attr->show(kobj, kobj_attr, buf);
715
716         up_read(&dev->dev_attr_rwsem);
717
718 out:
719         return res;
720 }
721
722 static ssize_t scst_dev_attr_store(struct kobject *kobj, struct attribute *attr,
723                           const char *buf, size_t count)
724 {
725         int res;
726         struct kobj_attribute *kobj_attr;
727         struct scst_device *dev;
728
729         dev = container_of(kobj, struct scst_device, dev_kobj);
730
731         if (down_read_trylock(&dev->dev_attr_rwsem) == 0) {
732                 res = -ENOENT;
733                 goto out;
734         }
735
736         kobj_attr = container_of(attr, struct kobj_attribute, attr);
737
738         res = kobj_attr->store(kobj, kobj_attr, buf, count);
739
740         up_read(&dev->dev_attr_rwsem);
741
742 out:
743         return res;
744 }
745
746 static struct sysfs_ops scst_dev_sysfs_ops = {
747         .show = scst_dev_attr_show,
748         .store = scst_dev_attr_store,
749 };
750
751 static struct kobj_type scst_device_ktype = {
752         .sysfs_ops = &scst_dev_sysfs_ops,
753         .release = scst_sysfs_device_release,
754         .default_attrs = scst_device_attrs,
755 };
756
757 int scst_create_device_sysfs(struct scst_device *dev)
758 {
759         int retval = 0;
760
761         TRACE_ENTRY();
762
763         init_rwsem(&dev->dev_attr_rwsem);
764
765         dev->dev_kobj_initialized = 1;
766
767         retval = kobject_init_and_add(&dev->dev_kobj, &scst_device_ktype,
768                                       scst_devices_kobj, dev->virt_name);
769         if (retval != 0) {
770                 PRINT_ERROR("Can't add device %s to sysfs", dev->virt_name);
771                 goto out;
772         }
773
774         /*
775          * In case of errors there's no need for additional cleanup, because
776          * it will be done by the _put function() called by the caller.
777          */
778
779         dev->dev_exp_kobj = kobject_create_and_add("exported",
780                                                    &dev->dev_kobj);
781         if (dev->dev_exp_kobj == NULL) {
782                 PRINT_ERROR("Can't create exported link for device %s",
783                         dev->virt_name);
784                 retval = -ENOMEM;
785                 goto out;
786         }
787
788         if (dev->scsi_dev != NULL) {
789                 retval = sysfs_create_link(&dev->dev_kobj,
790                         &dev->scsi_dev->sdev_dev.kobj, "scsi_device");
791                 if (retval != 0) {
792                         PRINT_ERROR("Can't create scsi_device link for dev %s",
793                                 dev->virt_name);
794                         goto out;
795                 }
796         }
797
798 out:
799         TRACE_EXIT_RES(retval);
800         return retval;
801 }
802
803 /*
804  * Must not be called under scst_mutex or there can be a deadlock with
805  * dev_attr_rwsem
806  */
807 void scst_device_sysfs_put(struct scst_device *dev)
808 {
809         TRACE_ENTRY();
810
811         if (dev->dev_kobj_initialized) {
812                 kobject_del(dev->dev_exp_kobj);
813                 kobject_put(dev->dev_exp_kobj);
814
815                 kobject_del(&dev->dev_kobj);
816
817                 down_write(&dev->dev_attr_rwsem);
818                 kobject_put(&dev->dev_kobj);
819         } else
820                 scst_free_device(dev);
821
822         TRACE_EXIT();
823         return;
824 }
825
826 /*
827  * Target sessions directory implementation
828  */
829
830 static ssize_t scst_sess_sysfs_commands_show(struct kobject *kobj,
831                             struct kobj_attribute *attr, char *buf)
832 {
833         struct scst_session *sess;
834
835         sess = container_of(kobj, struct scst_session, sess_kobj);
836
837         return sprintf(buf, "%i\n", atomic_read(&sess->sess_cmd_count));
838 }
839
840 static struct kobj_attribute session_commands_attr =
841         __ATTR(commands, S_IRUGO, scst_sess_sysfs_commands_show, NULL);
842
843 static ssize_t scst_sess_sysfs_active_commands_show(struct kobject *kobj,
844                             struct kobj_attribute *attr, char *buf)
845 {
846         int res;
847         struct scst_session *sess;
848         int active_cmds = 0, t;
849
850         if (mutex_lock_interruptible(&scst_mutex) != 0) {
851                 res = -EINTR;
852                 goto out;
853         }
854
855         sess = container_of(kobj, struct scst_session, sess_kobj);
856
857         for (t = TGT_DEV_HASH_SIZE-1; t >= 0; t--) {
858                 struct list_head *sess_tgt_dev_list_head =
859                         &sess->sess_tgt_dev_list_hash[t];
860                 struct scst_tgt_dev *tgt_dev;
861                 list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
862                                 sess_tgt_dev_list_entry) {
863                         active_cmds += atomic_read(&tgt_dev->tgt_dev_cmd_count);
864                 }
865         }
866
867         mutex_unlock(&scst_mutex);
868
869         res = sprintf(buf, "%i\n", active_cmds);
870
871 out:
872         return res;
873 }
874
875 static struct kobj_attribute session_active_commands_attr =
876         __ATTR(commands, S_IRUGO, scst_sess_sysfs_active_commands_show, NULL);
877
878 static ssize_t scst_sess_sysfs_initiator_name_show(struct kobject *kobj,
879                             struct kobj_attribute *attr, char *buf)
880 {
881         struct scst_session *sess;
882
883         sess = container_of(kobj, struct scst_session, sess_kobj);
884
885         return scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, "%s\n",
886                 sess->initiator_name);
887 }
888
889 static struct kobj_attribute session_initiator_name_attr =
890         __ATTR(initiator_name, S_IRUGO, scst_sess_sysfs_initiator_name_show, NULL);
891
892 static struct attribute *scst_session_attrs[] = {
893         &session_commands_attr.attr,
894         &session_active_commands_attr.attr,
895         &session_initiator_name_attr.attr,
896         NULL,
897 };
898
899 static void scst_sysfs_session_release(struct kobject *kobj)
900 {
901         struct scst_session *sess;
902
903         TRACE_ENTRY();
904
905         sess = container_of(kobj, struct scst_session, sess_kobj);
906
907         /* Let's make lockdep happy */
908         up_write(&sess->sess_attr_rwsem);
909
910         scst_release_session(sess);
911
912         TRACE_EXIT();
913         return;
914 }
915
916 static ssize_t scst_sess_attr_show(struct kobject *kobj, struct attribute *attr,
917                          char *buf)
918 {
919         int res;
920         struct kobj_attribute *kobj_attr;
921         struct scst_session *sess;
922
923         sess = container_of(kobj, struct scst_session, sess_kobj);
924
925         if (down_read_trylock(&sess->sess_attr_rwsem) == 0) {
926                 res = -ENOENT;
927                 goto out;
928         }
929
930         kobj_attr = container_of(attr, struct kobj_attribute, attr);
931
932         res = kobj_attr->show(kobj, kobj_attr, buf);
933
934         up_read(&sess->sess_attr_rwsem);
935
936 out:
937         return res;
938 }
939
940 static ssize_t scst_sess_attr_store(struct kobject *kobj, struct attribute *attr,
941                           const char *buf, size_t count)
942 {
943         int res;
944         struct kobj_attribute *kobj_attr;
945         struct scst_session *sess;
946
947         sess = container_of(kobj, struct scst_session, sess_kobj);
948
949         if (down_read_trylock(&sess->sess_attr_rwsem) == 0) {
950                 res = -ENOENT;
951                 goto out;
952         }
953
954         kobj_attr = container_of(attr, struct kobj_attribute, attr);
955
956         res = kobj_attr->store(kobj, kobj_attr, buf, count);
957
958         up_read(&sess->sess_attr_rwsem);
959
960 out:
961         return res;
962 }
963
964 static struct sysfs_ops scst_sess_sysfs_ops = {
965         .show = scst_sess_attr_show,
966         .store = scst_sess_attr_store,
967 };
968
969 static struct kobj_type scst_session_ktype = {
970         .sysfs_ops = &scst_sess_sysfs_ops,
971         .release = scst_sysfs_session_release,
972         .default_attrs = scst_session_attrs,
973 };
974
975 /* scst_mutex supposed to be locked */
976 int scst_create_sess_sysfs(struct scst_session *sess)
977 {
978         int retval = 0;
979         struct scst_session *s;
980         const struct attribute **pattr;
981         char *name = (char *)sess->initiator_name;
982         int len = strlen(name) + 1, n = 1;
983
984         TRACE_ENTRY();
985
986 restart:
987         list_for_each_entry(s, &sess->tgt->sess_list, sess_list_entry) {
988                 if (!s->sess_kobj_initialized)
989                         continue;
990
991                 if (strcmp(name, kobject_name(&s->sess_kobj)) == 0) {
992                         if (s == sess)
993                                 continue;
994
995                         TRACE_DBG("Dublicated session from the same initiator "
996                                 "%s found", name);
997
998                         if (name == sess->initiator_name) {
999                                 len = strlen(sess->initiator_name);
1000                                 len += 20;
1001                                 name = kmalloc(len, GFP_KERNEL);
1002                                 if (name == NULL) {
1003                                         PRINT_ERROR("Unable to allocate a "
1004                                                 "replacement name (size %d)",
1005                                                 len);
1006                                 }
1007                         }
1008
1009                         snprintf(name, len, "%s_%d", sess->initiator_name, n);
1010                         n++;
1011                         goto restart;
1012                 }
1013         }
1014
1015         init_rwsem(&sess->sess_attr_rwsem);
1016
1017         sess->sess_kobj_initialized = 1;
1018
1019         retval = kobject_init_and_add(&sess->sess_kobj, &scst_session_ktype,
1020                               sess->tgt->tgt_sess_kobj, name);
1021         if (retval != 0) {
1022                 PRINT_ERROR("Can't add session %s to sysfs", name);
1023                 goto out_free;
1024         }
1025
1026         /*
1027          * In case of errors there's no need for additional cleanup, because
1028          * it will be done by the _put function() called by the caller.
1029          */
1030
1031         pattr = sess->tgt->tgtt->sess_attrs;
1032         if (pattr != NULL) {
1033                 while (*pattr != NULL) {
1034                         retval = sysfs_create_file(&sess->sess_kobj, *pattr);
1035                         if (retval != 0) {
1036                                 PRINT_ERROR("Can't add sess attr %s for sess "
1037                                         "for initiator %s", (*pattr)->name,
1038                                         name);
1039                                 goto out_free;
1040                         }
1041                         pattr++;
1042                 }
1043         }
1044
1045 out_free:
1046         if (name != sess->initiator_name)
1047                 kfree(name);
1048
1049         TRACE_EXIT_RES(retval);
1050         return retval;
1051 }
1052
1053 /*
1054  * Must not be called under scst_mutex or there can be a deadlock with
1055  * sess_attr_rwsem
1056  */
1057 void scst_sess_sysfs_put(struct scst_session *sess)
1058 {
1059         TRACE_ENTRY();
1060
1061         if (sess->sess_kobj_initialized) {
1062                 kobject_del(&sess->sess_kobj);
1063
1064                 down_write(&sess->sess_attr_rwsem);
1065                 kobject_put(&sess->sess_kobj);
1066         } else
1067                 scst_release_session(sess);
1068
1069         TRACE_EXIT();
1070         return;
1071 }
1072
1073 /*
1074  * Target luns directory implementation
1075  */
1076
1077 static void scst_acg_dev_release(struct kobject *kobj)
1078 {
1079         struct scst_acg_dev *acg_dev;
1080
1081         TRACE_ENTRY();
1082
1083         acg_dev = container_of(kobj, struct scst_acg_dev, acg_dev_kobj);
1084
1085         scst_acg_dev_destroy(acg_dev);
1086
1087         TRACE_EXIT();
1088         return;
1089 }
1090
1091 static ssize_t scst_lun_rd_only_show(struct kobject *kobj,
1092                                    struct kobj_attribute *attr,
1093                                    char *buf)
1094 {
1095         struct scst_acg_dev *acg_dev;
1096
1097         acg_dev = container_of(kobj, struct scst_acg_dev, acg_dev_kobj);
1098
1099         return sprintf(buf, "%d\n",
1100                 (acg_dev->rd_only || acg_dev->dev->rd_only) ? 1 : 0);
1101 }
1102
1103 static struct kobj_attribute lun_options_attr =
1104         __ATTR(read_only, S_IRUGO, scst_lun_rd_only_show, NULL);
1105
1106 static struct attribute *lun_attrs[] = {
1107         &lun_options_attr.attr,
1108         NULL,
1109 };
1110
1111 static struct kobj_type acg_dev_ktype = {
1112         .sysfs_ops = &scst_sysfs_ops,
1113         .release = scst_acg_dev_release,
1114         .default_attrs = lun_attrs,
1115 };
1116
1117 int scst_create_acg_dev_sysfs(struct scst_acg *acg, unsigned int virt_lun,
1118         struct kobject *parent)
1119 {
1120         int retval;
1121         struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
1122         char str[20];
1123
1124         TRACE_ENTRY();
1125
1126         list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
1127                             acg_dev_list_entry) {
1128                 if (acg_dev_tmp->lun == virt_lun) {
1129                         acg_dev = acg_dev_tmp;
1130                         break;
1131                 }
1132         }
1133         if (acg_dev == NULL) {
1134                 PRINT_ERROR("%s", "acg_dev lookup for kobject creation failed");
1135                 retval = -EINVAL;
1136                 goto out;
1137         }
1138
1139         snprintf(str, sizeof(str), "export%u",
1140                 acg_dev->dev->dev_exported_lun_num++);
1141
1142         kobject_get(&acg_dev->dev->dev_kobj);
1143
1144         acg_dev->acg_dev_kobj_initialized = 1;
1145
1146         retval = kobject_init_and_add(&acg_dev->acg_dev_kobj, &acg_dev_ktype,
1147                                       parent, "%u", virt_lun);
1148         if (retval != 0) {
1149                 PRINT_ERROR("Can't add acg %s to sysfs", acg->acg_name);
1150                 goto out;
1151         }
1152
1153         /*
1154          * In case of errors there's no need for additional cleanup, because
1155          * it will be done by the _put function() called by the caller.
1156          */
1157
1158         retval = sysfs_create_link(acg_dev->dev->dev_exp_kobj,
1159                                    &acg_dev->acg_dev_kobj, str);
1160         if (retval != 0) {
1161                 PRINT_ERROR("Can't create acg %s LUN link", acg->acg_name);
1162                 goto out;
1163         }
1164
1165         retval = sysfs_create_link(&acg_dev->acg_dev_kobj,
1166                         &acg_dev->dev->dev_kobj, "device");
1167         if (retval != 0) {
1168                 PRINT_ERROR("Can't create acg %s device link", acg->acg_name);
1169                 goto out;
1170         }
1171
1172 out:
1173         return retval;
1174 }
1175
1176 static ssize_t __scst_luns_mgmt_store(struct scst_acg *acg,
1177         struct kobject *kobj, const char *buf, size_t count)
1178 {
1179         int res, virt = 0, read_only = 0, action;
1180         char *buffer, *p, *e = NULL;
1181         unsigned int host, channel = 0, id = 0, lun = 0, virt_lun;
1182         struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
1183         struct scst_device *d, *dev = NULL;
1184
1185 #define SCST_LUN_ACTION_ADD     1
1186 #define SCST_LUN_ACTION_DEL     2
1187 #define SCST_LUN_ACTION_REPLACE 3
1188 #define SCST_LUN_ACTION_CLEAR   4
1189
1190         TRACE_ENTRY();
1191
1192         buffer = kzalloc(count+1, GFP_KERNEL);
1193         if (buffer == NULL) {
1194                 res = -ENOMEM;
1195                 goto out;
1196         }
1197
1198         memcpy(buffer, buf, count);
1199         buffer[count] = '\0';
1200         p = buffer;
1201
1202         p = buffer;
1203         if (p[strlen(p) - 1] == '\n')
1204                 p[strlen(p) - 1] = '\0';
1205         if (strncasecmp("add", p, 3) == 0) {
1206                 p += 3;
1207                 action = SCST_LUN_ACTION_ADD;
1208         } else if (strncasecmp("del", p, 3) == 0) {
1209                 p += 3;
1210                 action = SCST_LUN_ACTION_DEL;
1211         } else if (!strncasecmp("replace", p, 7)) {
1212                 p += 7;
1213                 action = SCST_LUN_ACTION_REPLACE;
1214         } else if (!strncasecmp("clear", p, 5)) {
1215                 p += 5;
1216                 action = SCST_LUN_ACTION_CLEAR;
1217         } else {
1218                 PRINT_ERROR("Unknown action \"%s\"", p);
1219                 res = -EINVAL;
1220                 goto out_free;
1221         }
1222
1223         res = scst_suspend_activity(true);
1224         if (res != 0)
1225                 goto out_free;
1226
1227         if (mutex_lock_interruptible(&scst_mutex) != 0) {
1228                 res = -EINTR;
1229                 goto out_free_resume;
1230         }
1231
1232         if (action != SCST_LUN_ACTION_CLEAR) {
1233                 if (!isspace(*p)) {
1234                         PRINT_ERROR("%s", "Syntax error");
1235                         res = -EINVAL;
1236                         goto out_free_up;
1237                 }
1238
1239                 while (isspace(*p) && *p != '\0')
1240                         p++;
1241                 e = p; /* save p */
1242                 host = simple_strtoul(p, &p, 0);
1243                 if (*p == ':') {
1244                         channel = simple_strtoul(p + 1, &p, 0);
1245                         id = simple_strtoul(p + 1, &p, 0);
1246                         lun = simple_strtoul(p + 1, &p, 0);
1247                         e = p;
1248                 } else {
1249                         virt++;
1250                         p = e; /* restore p */
1251                         while (!isspace(*e) && *e != '\0')
1252                                 e++;
1253                         *e = '\0';
1254                 }
1255
1256                 list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
1257                         if (virt) {
1258                                 if (d->virt_id && !strcmp(d->virt_name, p)) {
1259                                         dev = d;
1260                                         TRACE_DBG("Virt device %p (%s) found",
1261                                                   dev, p);
1262                                         break;
1263                                 }
1264                         } else {
1265                                 if (d->scsi_dev &&
1266                                     d->scsi_dev->host->host_no == host &&
1267                                     d->scsi_dev->channel == channel &&
1268                                     d->scsi_dev->id == id &&
1269                                     d->scsi_dev->lun == lun) {
1270                                         dev = d;
1271                                         TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
1272                                                   dev, host, channel, id, lun);
1273                                         break;
1274                                 }
1275                         }
1276                 }
1277                 if (dev == NULL) {
1278                         if (virt) {
1279                                 PRINT_ERROR("Virt device '%s' not found", p);
1280                         } else {
1281                                 PRINT_ERROR("Device %d:%d:%d:%d not found",
1282                                             host, channel, id, lun);
1283                         }
1284                         res = -EINVAL;
1285                         goto out_free_up;
1286                 }
1287         }
1288
1289         switch (action) {
1290         case SCST_LUN_ACTION_ADD:
1291         case SCST_LUN_ACTION_REPLACE:
1292         {
1293                 bool dev_replaced = false;
1294
1295                 e++;
1296                 while (isspace(*e) && *e != '\0')
1297                         e++;
1298                 virt_lun = simple_strtoul(e, &e, 0);
1299
1300                 while (isspace(*e) && *e != '\0')
1301                         e++;
1302
1303                 if (*e != '\0') {
1304                         if ((strncasecmp("READ_ONLY", e, 9) == 0) &&
1305                             (isspace(e[9]) || (e[9] == '\0')))
1306                                 read_only = 1;
1307                         else {
1308                                 PRINT_ERROR("Unknown option \"%s\"", e);
1309                                 res = -EINVAL;
1310                                 goto out_free_up;
1311                         }
1312                 }
1313
1314                 acg_dev = NULL;
1315                 list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
1316                                     acg_dev_list_entry) {
1317                         if (acg_dev_tmp->lun == virt_lun) {
1318                                 acg_dev = acg_dev_tmp;
1319                                 break;
1320                         }
1321                 }
1322
1323                 if (acg_dev != NULL) {
1324                         if (action == SCST_LUN_ACTION_ADD) {
1325                                 PRINT_ERROR("virt lun %d already exists in "
1326                                         "group %s", virt_lun, acg->acg_name);
1327                                 res = -EEXIST;
1328                                 goto out_free_up;
1329                         } else {
1330                                 /* Replace */
1331                                 res = scst_acg_remove_dev(acg, acg_dev->dev,
1332                                                 false);
1333                                 if (res != 0)
1334                                         goto out_free_up;
1335
1336                                 dev_replaced = true;
1337                         }
1338                 }
1339
1340                 res = scst_acg_add_dev(acg, dev, virt_lun, read_only,
1341                                         !dev_replaced);
1342                 if (res != 0)
1343                         goto out_free_up;
1344
1345                 res = scst_create_acg_dev_sysfs(acg, virt_lun, kobj);
1346                 if (res != 0) {
1347                         PRINT_ERROR("%s", "Creation of acg_dev kobject failed");
1348                         goto out_remove_acg_dev;
1349                 }
1350
1351                 if (dev_replaced) {
1352                         struct scst_tgt_dev *tgt_dev;
1353
1354                         list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
1355                                 dev_tgt_dev_list_entry) {
1356                                 if ((tgt_dev->acg_dev->acg == acg) &&
1357                                     (tgt_dev->lun == virt_lun)) {
1358                                         TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED"
1359                                                 " on tgt_dev %p", tgt_dev);
1360                                         scst_gen_aen_or_ua(tgt_dev,
1361                                                 SCST_LOAD_SENSE(scst_sense_inquery_data_changed));
1362                                 }
1363                         }
1364                 }
1365
1366                 break;
1367         }
1368         case SCST_LUN_ACTION_DEL:
1369                 res = scst_acg_remove_dev(acg, dev, true);
1370                 if (res != 0)
1371                         goto out_free_up;
1372                 break;
1373         case SCST_LUN_ACTION_CLEAR:
1374                 PRINT_INFO("Removed all devices from group %s",
1375                         acg->acg_name);
1376                 list_for_each_entry_safe(acg_dev, acg_dev_tmp,
1377                                          &acg->acg_dev_list,
1378                                          acg_dev_list_entry) {
1379                         res = scst_acg_remove_dev(acg, acg_dev->dev,
1380                                 list_is_last(&acg_dev->acg_dev_list_entry,
1381                                              &acg->acg_dev_list));
1382                         if (res)
1383                                 goto out_free_up;
1384                 }
1385                 break;
1386         }
1387
1388         res = count;
1389
1390 out_free_up:
1391         mutex_unlock(&scst_mutex);
1392
1393 out_free_resume:
1394         scst_resume_activity();
1395
1396 out_free:
1397         kfree(buffer);
1398
1399 out:
1400         TRACE_EXIT_RES(res);
1401         return res;
1402
1403 out_remove_acg_dev:
1404         scst_acg_remove_dev(acg, dev, true);
1405         goto out_free_up;
1406
1407 #undef SCST_LUN_ACTION_ADD
1408 #undef SCST_LUN_ACTION_DEL
1409 #undef SCST_LUN_ACTION_REPLACE
1410 #undef SCST_LUN_ACTION_CLEAR
1411 }
1412
1413 static ssize_t scst_luns_mgmt_show(struct kobject *kobj,
1414                                    struct kobj_attribute *attr,
1415                                    char *buf)
1416 {
1417         static char *help = "Usage: echo \"add|del H:C:I:L lun [READ_ONLY]\" "
1418                                         ">mgmt\n"
1419                             "       echo \"add|del VNAME lun [READ_ONLY]\" "
1420                                         ">mgmt\n"
1421                             "       echo \"replace H:C:I:L lun [READ_ONLY]\" "
1422                                         ">mgmt\n"
1423                             "       echo \"replace VNAME lun [READ_ONLY]\" "
1424                                         ">mgmt\n"
1425                             "       echo \"clear\" "
1426                                         ">mgmt\n";
1427
1428         return sprintf(buf, help);
1429 }
1430
1431 static ssize_t scst_luns_mgmt_store(struct kobject *kobj,
1432                                     struct kobj_attribute *attr,
1433                                     const char *buf, size_t count)
1434 {
1435         int res;
1436         struct scst_acg *acg;
1437         struct scst_tgt *tgt;
1438
1439         tgt = container_of(kobj->parent, struct scst_tgt, tgt_kobj);
1440         acg = tgt->default_acg;
1441         res = __scst_luns_mgmt_store(acg, kobj, buf, count);
1442
1443         TRACE_EXIT_RES(res);
1444         return res;
1445 }
1446
1447 static int scst_create_acg_sysfs(struct scst_tgt *tgt,
1448         struct scst_acg *acg)
1449 {
1450         int retval = 0;
1451
1452         TRACE_ENTRY();
1453
1454         acg->acg_kobj_initialized = 1;
1455
1456         retval = kobject_init_and_add(&acg->acg_kobj, &acg_ktype,
1457                 tgt->tgt_ini_grp_kobj, acg->acg_name);
1458         if (retval != 0) {
1459                 PRINT_ERROR("Can't add acg '%s' to sysfs", acg->acg_name);
1460                 goto out;
1461         }
1462
1463         acg->luns_kobj = kobject_create_and_add("luns", &acg->acg_kobj);
1464         if (acg->luns_kobj == NULL) {
1465                 PRINT_ERROR("Can't create luns kobj for tgt %s",
1466                         tgt->tgt_name);
1467                 retval = -ENOMEM;
1468                 goto out;
1469         }
1470
1471         retval = sysfs_create_file(acg->luns_kobj, &scst_acg_luns_mgmt.attr);
1472         if (retval != 0) {
1473                 PRINT_ERROR("Can't add tgt attr %s for tgt %s",
1474                         scst_acg_luns_mgmt.attr.name, tgt->tgt_name);
1475                 goto out;
1476         }
1477
1478         acg->initiators_kobj = kobject_create_and_add("initiators",
1479                 &acg->acg_kobj);
1480         if (acg->initiators_kobj == NULL) {
1481                 PRINT_ERROR("Can't create initiators kobj for tgt %s",
1482                         tgt->tgt_name);
1483                 retval = -ENOMEM;
1484                 goto out;
1485         }
1486
1487         retval = sysfs_create_file(acg->initiators_kobj,
1488                 &scst_acg_ini_mgmt.attr);
1489         if (retval != 0) {
1490                 PRINT_ERROR("Can't add tgt attr %s for tgt %s",
1491                         scst_acg_ini_mgmt.attr.name, tgt->tgt_name);
1492                 goto out;
1493         }
1494 out:
1495         TRACE_EXIT_RES(retval);
1496         return retval;
1497 }
1498
1499 void scst_acg_sysfs_put(struct scst_acg *acg)
1500 {
1501         TRACE_ENTRY();
1502
1503         if (acg->acg_kobj_initialized) {
1504                 scst_clear_acg(acg);
1505
1506                 kobject_del(acg->luns_kobj);
1507                 kobject_put(acg->luns_kobj);
1508
1509                 kobject_del(acg->initiators_kobj);
1510                 kobject_put(acg->initiators_kobj);
1511
1512                 kobject_del(&acg->acg_kobj);
1513                 kobject_put(&acg->acg_kobj);
1514         } else
1515                 scst_destroy_acg(acg);
1516
1517         TRACE_EXIT();
1518         return;
1519 }
1520
1521 static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj,
1522         struct kobj_attribute *attr, char *buf)
1523 {
1524         static char *help = "Usage: echo \"create GROUP_NAME\" "
1525                                         ">mgmt\n"
1526                             "       echo \"del GROUP_NAME\" "
1527                                         ">mgmt\n";
1528
1529         return sprintf(buf, help);
1530 }
1531
1532 static ssize_t scst_ini_group_mgmt_store(struct kobject *kobj,
1533         struct kobj_attribute *attr, const char *buf, size_t count)
1534 {
1535         int res, action;
1536         int len;
1537         char *name;
1538         char *buffer, *p, *e = NULL;
1539         struct scst_acg *a, *acg = NULL;
1540         struct scst_tgt *tgt;
1541
1542 #define SCST_INI_GROUP_ACTION_CREATE    1
1543 #define SCST_INI_GROUP_ACTION_DEL       2
1544
1545         TRACE_ENTRY();
1546
1547         tgt = container_of(kobj->parent, struct scst_tgt, tgt_kobj);
1548
1549         buffer = kzalloc(count+1, GFP_KERNEL);
1550         if (buffer == NULL) {
1551                 res = -ENOMEM;
1552                 goto out;
1553         }
1554
1555         memcpy(buffer, buf, count);
1556         buffer[count] = '\0';
1557         p = buffer;
1558
1559         p = buffer;
1560         if (p[strlen(p) - 1] == '\n')
1561                 p[strlen(p) - 1] = '\0';
1562         if (strncasecmp("create ", p, 7) == 0) {
1563                 p += 7;
1564                 action = SCST_INI_GROUP_ACTION_CREATE;
1565         } else if (strncasecmp("del ", p, 4) == 0) {
1566                 p += 4;
1567                 action = SCST_INI_GROUP_ACTION_DEL;
1568         } else {
1569                 PRINT_ERROR("Unknown action \"%s\"", p);
1570                 res = -EINVAL;
1571                 goto out_free;
1572         }
1573
1574         res = scst_suspend_activity(true);
1575         if (res != 0)
1576                 goto out_free;
1577
1578         if (mutex_lock_interruptible(&scst_mutex) != 0) {
1579                 res = -EINTR;
1580                 goto out_free_resume;
1581         }
1582
1583         while (isspace(*p) && *p != '\0')
1584                 p++;
1585         e = p;
1586         while (!isspace(*e) && *e != '\0')
1587                 e++;
1588         *e = '\0';
1589
1590         if (p[0] == '\0') {
1591                 PRINT_ERROR("%s", "Group name required");
1592                 res = -EINVAL;
1593                 goto out_free_up;
1594         }
1595
1596         list_for_each_entry(a, &tgt->acg_list, acg_list_entry) {
1597                 if (strcmp(a->acg_name, p) == 0) {
1598                         TRACE_DBG("group (acg) %p %s found",
1599                                   a, a->acg_name);
1600                         acg = a;
1601                         break;
1602                 }
1603         }
1604
1605         switch (action) {
1606         case SCST_INI_GROUP_ACTION_CREATE:
1607                 TRACE_DBG("Creating group '%s'", p);
1608                 if (acg != NULL) {
1609                         PRINT_ERROR("acg name %s exist", p);
1610                         res = -EINVAL;
1611                         goto out_free_up;
1612                 }
1613
1614                 len = strlen(p) + 1;
1615                 name = kmalloc(len, GFP_KERNEL);
1616                 if (name == NULL) {
1617                         PRINT_ERROR("%s", "Allocation of name failed");
1618                         res = -ENOMEM;
1619                         goto out_free_up;
1620                 }
1621                 strncpy(name, p, len);
1622
1623                 acg = scst_alloc_add_acg(tgt, name);
1624                 kfree(name);
1625                 if (acg == NULL)
1626                         goto out_free_up;
1627
1628                 res = scst_create_acg_sysfs(tgt, acg);
1629                 if (res != 0)
1630                         goto out_free_acg;
1631                 break;
1632         case SCST_INI_GROUP_ACTION_DEL:
1633                 TRACE_DBG("Deleting group '%s'", p);
1634                 if (acg == NULL) {
1635                         PRINT_ERROR("Group %s not found", p);
1636                         res = -EINVAL;
1637                         goto out_free_up;
1638                 }
1639                 if (!scst_acg_sess_is_empty(acg)) {
1640                         PRINT_ERROR("Group %s is not empty", acg->acg_name);
1641                         res = -EBUSY;
1642                         goto out_free_up;
1643                 }
1644                 scst_acg_sysfs_put(acg);
1645                 break;
1646         }
1647
1648         res = count;
1649
1650 out_free_up:
1651         mutex_unlock(&scst_mutex);
1652
1653 out_free_resume:
1654         scst_resume_activity();
1655
1656 out_free:
1657         kfree(buffer);
1658
1659 out:
1660         TRACE_EXIT_RES(res);
1661         return res;
1662
1663 out_free_acg:
1664         scst_acg_sysfs_put(acg);
1665         goto out_free_up;
1666
1667 #undef SCST_LUN_ACTION_CREATE
1668 #undef SCST_LUN_ACTION_DEL
1669 }
1670
1671 int scst_create_acn_sysfs(struct scst_acg *acg, struct scst_acn *acn)
1672 {
1673         int retval = 0;
1674         int len;
1675         struct kobj_attribute *attr = NULL;
1676
1677         TRACE_ENTRY();
1678
1679         acn->acn_attr = NULL;
1680
1681         attr = kzalloc(sizeof(struct kobj_attribute), GFP_KERNEL);
1682         if (attr == NULL) {
1683                 PRINT_ERROR("Unable to allocate attributes for initiator '%s'",
1684                         acn->name);
1685                 retval = -ENOMEM;
1686                 goto out;
1687         }
1688
1689         len = strlen(acn->name) + 1;
1690         attr->attr.name = kzalloc(len, GFP_KERNEL);
1691         if (attr->attr.name == NULL) {
1692                 PRINT_ERROR("Unable to allocate attributes for initiator '%s'",
1693                         acn->name);
1694                 retval = -ENOMEM;
1695                 goto out_free;
1696         }
1697         strncpy((char *)attr->attr.name, acn->name, len);
1698
1699         attr->attr.owner = THIS_MODULE;
1700         attr->attr.mode = S_IRUGO;
1701         attr->show = scst_acn_file_show;
1702         attr->store = NULL;
1703
1704         retval = sysfs_create_file(acg->initiators_kobj, &attr->attr);
1705         if (retval != 0) {
1706                 PRINT_ERROR("Unable to allocate initiator '%s' for group '%s'",
1707                         acn->name, acg->acg_name);
1708                 kfree(attr->attr.name);
1709                 goto out_free;
1710         }
1711
1712         acn->acn_attr = attr;
1713
1714 out:
1715         TRACE_EXIT_RES(retval);
1716         return retval;
1717
1718 out_free:
1719         kfree(attr);
1720         goto out;
1721 }
1722
1723 void scst_acn_sysfs_del(struct scst_acg *acg, struct scst_acn *acn,
1724         bool reassign)
1725 {
1726         TRACE_ENTRY();
1727
1728         if (acn->acn_attr != NULL) {
1729                 sysfs_remove_file(acg->initiators_kobj,
1730                         &acn->acn_attr->attr);
1731                 kfree(acn->acn_attr->attr.name);
1732                 kfree(acn->acn_attr);
1733         }
1734         scst_acg_remove_acn(acn);
1735         if (reassign)
1736                 scst_check_reassign_sessions();
1737
1738         TRACE_EXIT();
1739         return;
1740 }
1741
1742 static ssize_t scst_acn_file_show(struct kobject *kobj,
1743         struct kobj_attribute *attr, char *buf)
1744 {
1745         return scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, "%s\n",
1746                 attr->attr.name);
1747 }
1748
1749 static ssize_t scst_acg_luns_mgmt_show(struct kobject *kobj,
1750                                    struct kobj_attribute *attr,
1751                                    char *buf)
1752 {
1753         static char *help = "Usage: echo \"add|del H:C:I:L lun [READ_ONLY]\" "
1754                                         ">mgmt\n"
1755                             "       echo \"add|del VNAME lun [READ_ONLY]\" "
1756                                         ">mgmt\n"
1757                             "       echo \"replace H:C:I:L lun [READ_ONLY]\" "
1758                                         ">mgmt\n"
1759                             "       echo \"replace VNAME lun [READ_ONLY]\" "
1760                                         ">mgmt\n"
1761                             "       echo \"clear\" "
1762                                         ">mgmt\n";
1763
1764         return sprintf(buf, help);
1765 }
1766
1767 static ssize_t scst_acg_luns_mgmt_store(struct kobject *kobj,
1768                                     struct kobj_attribute *attr,
1769                                     const char *buf, size_t count)
1770 {
1771         int res;
1772         struct scst_acg *acg;
1773
1774         acg = container_of(kobj->parent, struct scst_acg, acg_kobj);
1775         res = __scst_luns_mgmt_store(acg, kobj, buf, count);
1776
1777         TRACE_EXIT_RES(res);
1778         return res;
1779 }
1780
1781 static ssize_t scst_acg_ini_mgmt_show(struct kobject *kobj,
1782         struct kobj_attribute *attr, char *buf)
1783 {
1784         static char *help = "Usage: echo \"add INITIATOR_NAME\" "
1785                                         ">mgmt\n"
1786                             "       echo \"del INITIATOR_NAME\" "
1787                                         ">mgmt\n"
1788                             "       echo \"move INITIATOR_NAME DEST_GROUP_NAME\" "
1789                                         ">mgmt\n"
1790                             "       echo \"clear\" "
1791                                         ">mgmt\n";
1792
1793         return sprintf(buf, help);
1794 }
1795
1796 static ssize_t scst_acg_ini_mgmt_store(struct kobject *kobj,
1797         struct kobj_attribute *attr, const char *buf, size_t count)
1798 {
1799         int res, action;
1800         char *buffer, *p, *e = NULL;
1801         char *name = NULL, *group = NULL;
1802         struct scst_acg *acg = NULL, *acg_dest = NULL;
1803         struct scst_tgt *tgt = NULL;
1804         struct scst_acn *acn = NULL, *acn_tmp;
1805
1806 #define SCST_ACG_ACTION_INI_ADD         1
1807 #define SCST_ACG_ACTION_INI_DEL         2
1808 #define SCST_ACG_ACTION_INI_CLEAR       3
1809 #define SCST_ACG_ACTION_INI_MOVE        4
1810
1811         TRACE_ENTRY();
1812
1813         acg = container_of(kobj->parent, struct scst_acg, acg_kobj);
1814
1815         buffer = kzalloc(count+1, GFP_KERNEL);
1816         if (buffer == NULL) {
1817                 res = -ENOMEM;
1818                 goto out;
1819         }
1820
1821         memcpy(buffer, buf, count);
1822         buffer[count] = '\0';
1823         p = buffer;
1824
1825         p = buffer;
1826         if (p[strlen(p) - 1] == '\n')
1827                 p[strlen(p) - 1] = '\0';
1828
1829         if (strncasecmp("add", p, 3) == 0) {
1830                 p += 3;
1831                 action = SCST_ACG_ACTION_INI_ADD;
1832         } else if (strncasecmp("del", p, 3) == 0) {
1833                 p += 3;
1834                 action = SCST_ACG_ACTION_INI_DEL;
1835         } else if (strncasecmp("clear", p, 5) == 0) {
1836                 p += 5;
1837                 action = SCST_ACG_ACTION_INI_CLEAR;
1838         } else if (strncasecmp("move", p, 4) == 0) {
1839                 p += 4;
1840                 action = SCST_ACG_ACTION_INI_MOVE;
1841         } else {
1842                 PRINT_ERROR("Unknown action \"%s\"", p);
1843                 res = -EINVAL;
1844                 goto out_free;
1845         }
1846
1847         if (action != SCST_ACG_ACTION_INI_CLEAR)
1848                 if (!isspace(*p)) {
1849                         PRINT_ERROR("%s", "Syntax error");
1850                         res = -EINVAL;
1851                         goto out_free;
1852                 }
1853
1854         res = scst_suspend_activity(true);
1855         if (res != 0)
1856                 goto out_free;
1857
1858         if (mutex_lock_interruptible(&scst_mutex) != 0) {
1859                 res = -EINTR;
1860                 goto out_free_resume;
1861         }
1862
1863         if (action != SCST_ACG_ACTION_INI_CLEAR)
1864                 while (isspace(*p) && *p != '\0')
1865                         p++;
1866
1867         switch (action) {
1868         case SCST_ACG_ACTION_INI_ADD:
1869                 e = p;
1870                 while (!isspace(*e) && *e != '\0')
1871                         e++;
1872                 *e = '\0';
1873                 name = p;
1874
1875                 if (name[0] == '\0') {
1876                         PRINT_ERROR("%s", "Invalid initiator name");
1877                         res = -EINVAL;
1878                         goto out_free_up;
1879                 }
1880
1881                 res = scst_acg_add_name(acg, name);
1882                 if (res != 0)
1883                         goto out_free_up;
1884                 break;
1885         case SCST_ACG_ACTION_INI_DEL:
1886                 e = p;
1887                 while (!isspace(*e) && *e != '\0')
1888                         e++;
1889                 *e = '\0';
1890                 name = p;
1891
1892                 if (name[0] == '\0') {
1893                         PRINT_ERROR("%s", "Invalid initiator name");
1894                         res = -EINVAL;
1895                         goto out_free_up;
1896                 }
1897
1898                 acn = scst_acg_find_name(acg, name);
1899                 if (acn == NULL) {
1900                         PRINT_ERROR("Unable to find "
1901                                 "initiator '%s' in group '%s'",
1902                                 name, acg->acg_name);
1903                         res = -EINVAL;
1904                         goto out_free_up;
1905                 }
1906                 scst_acn_sysfs_del(acg, acn, true);
1907                 break;
1908         case SCST_ACG_ACTION_INI_CLEAR:
1909                 list_for_each_entry_safe(acn, acn_tmp, &acg->acn_list,
1910                                 acn_list_entry) {
1911                         scst_acn_sysfs_del(acg, acn, false);
1912                 }
1913                 scst_check_reassign_sessions();
1914                 break;
1915         case SCST_ACG_ACTION_INI_MOVE:
1916                 e = p;
1917                 while (!isspace(*e) && *e != '\0')
1918                         e++;
1919                 if (*e == '\0') {
1920                         PRINT_ERROR("%s", "Too few parameters");
1921                         res = -EINVAL;
1922                         goto out_free_up;
1923                 }
1924                 *e = '\0';
1925                 name = p;
1926
1927                 if (name[0] == '\0') {
1928                         PRINT_ERROR("%s", "Invalid initiator name");
1929                         res = -EINVAL;
1930                         goto out_free_up;
1931                 }
1932
1933                 e++;
1934                 p = e;
1935                 while (!isspace(*e) && *e != '\0')
1936                         e++;
1937                 *e = '\0';
1938                 group = p;
1939
1940                 if (group[0] == '\0') {
1941                         PRINT_ERROR("%s", "Invalid group name");
1942                         res = -EINVAL;
1943                         goto out_free_up;
1944                 }
1945
1946                 TRACE_DBG("Move initiator '%s' to group '%s'",
1947                         name, group);
1948
1949                 /*
1950                  * Better get tgt from hierarchy tgt_kobj -> tgt_ini_grp_kobj ->
1951                  * acg_kobj -> initiators_kobj than have direct pointer to tgt
1952                  * in struct acg and have a headache to care about its possible
1953                  * wrong dereference on the destruction time.
1954                  */
1955                 {
1956                         struct kobject *k;
1957
1958                         /* acg_kobj */
1959                         k = kobj->parent;
1960                         if (k == NULL) {
1961                                 res = -EINVAL;
1962                                 goto out_free_up;
1963                         }
1964                         /* tgt_ini_grp_kobj */
1965                         k = k->parent;
1966                         if (k == NULL) {
1967                                 res = -EINVAL;
1968                                 goto out_free_up;
1969                         }
1970                         /* tgt_kobj */
1971                         k = k->parent;
1972                         if (k == NULL) {
1973                                 res = -EINVAL;
1974                                 goto out_free_up;
1975                         }
1976
1977                         tgt = container_of(k, struct scst_tgt, tgt_kobj);
1978                 }
1979
1980                 acn = scst_acg_find_name(acg, name);
1981                 if (acn == NULL) {
1982                         PRINT_ERROR("Unable to find "
1983                                 "initiator '%s' in group '%s'",
1984                                 name, acg->acg_name);
1985                         res = -EINVAL;
1986                         goto out_free_up;
1987                 }
1988                 acg_dest = scst_tgt_find_acg(tgt, group);
1989                 if (acg_dest == NULL) {
1990                         PRINT_ERROR("Unable to find group '%s' in target '%s'",
1991                                 group, tgt->tgt_name);
1992                         res = -EINVAL;
1993                         goto out_free_up;
1994                 }
1995                 if (scst_acg_find_name(acg_dest, name) != NULL) {
1996                         PRINT_ERROR("Initiator '%s' already exists in group '%s'",
1997                                 name, acg_dest->acg_name);
1998                         res = -EEXIST;
1999                         goto out_free_up;
2000                 }
2001                 scst_acn_sysfs_del(acg, acn, false);
2002
2003                 res = scst_acg_add_name(acg_dest, name);
2004                 if (res != 0)
2005                         goto out_free_up;
2006                 break;
2007         }
2008
2009         res = count;
2010
2011 out_free_up:
2012         mutex_unlock(&scst_mutex);
2013
2014 out_free_resume:
2015         scst_resume_activity();
2016
2017 out_free:
2018         kfree(buffer);
2019
2020 out:
2021         TRACE_EXIT_RES(res);
2022         return res;
2023
2024 #undef SCST_ACG_ACTION_INI_ADD
2025 #undef SCST_ACG_ACTION_INI_DEL
2026 #undef SCST_ACG_ACTION_INI_CLEAR
2027 #undef SCST_ACG_ACTION_INI_MOVE
2028 }
2029
2030 /*
2031  * SGV directory implementation
2032  */
2033
2034 static struct kobj_attribute sgv_stat_attr =
2035         __ATTR(stats, S_IRUGO | S_IWUSR, sgv_sysfs_stat_show,
2036                 sgv_sysfs_stat_reset);
2037
2038 static struct attribute *sgv_attrs[] = {
2039         &sgv_stat_attr.attr,
2040         NULL,
2041 };
2042
2043 static void sgv_kobj_release(struct kobject *kobj)
2044 {
2045         struct sgv_pool *pool;
2046
2047         TRACE_ENTRY();
2048
2049         pool = container_of(kobj, struct sgv_pool, sgv_kobj);
2050
2051         sgv_pool_destroy(pool);
2052
2053         TRACE_EXIT();
2054         return;
2055 }
2056
2057 static struct kobj_type sgv_pool_ktype = {
2058         .sysfs_ops = &scst_sysfs_ops,
2059         .release = sgv_kobj_release,
2060         .default_attrs = sgv_attrs,
2061 };
2062
2063 int scst_create_sgv_sysfs(struct sgv_pool *pool)
2064 {
2065         int retval;
2066
2067         TRACE_ENTRY();
2068
2069         pool->sgv_kobj_initialized = 1;
2070
2071         retval = kobject_init_and_add(&pool->sgv_kobj, &sgv_pool_ktype,
2072                         scst_sgv_kobj, pool->name);
2073         if (retval != 0) {
2074                 PRINT_ERROR("Can't add sgv pool %s to sysfs", pool->name);
2075                 goto out;
2076         }
2077
2078 out:
2079         TRACE_EXIT_RES(retval);
2080         return retval;
2081 }
2082
2083 /* pool can be dead upon exit from this function! */
2084 void scst_sgv_sysfs_put(struct sgv_pool *pool)
2085 {
2086         if (pool->sgv_kobj_initialized) {
2087                 kobject_del(&pool->sgv_kobj);
2088                 kobject_put(&pool->sgv_kobj);
2089         } else
2090                 sgv_pool_destroy(pool);
2091         return;
2092 }
2093
2094 static struct kobj_attribute sgv_global_stat_attr =
2095         __ATTR(global_stats, S_IRUGO | S_IWUSR, sgv_sysfs_global_stat_show,
2096                 sgv_sysfs_global_stat_reset);
2097
2098 static struct attribute *sgv_default_attrs[] = {
2099         &sgv_global_stat_attr.attr,
2100         NULL,
2101 };
2102
2103 static struct kobj_type sgv_ktype = {
2104         .sysfs_ops = &scst_sysfs_ops,
2105         .release = scst_sysfs_release,
2106         .default_attrs = sgv_default_attrs,
2107 };
2108
2109 /*
2110  * SCST sysfs root directory implementation
2111  */
2112
2113 static ssize_t scst_threads_show(struct kobject *kobj,
2114         struct kobj_attribute *attr, char *buf)
2115 {
2116         int count;
2117
2118         TRACE_ENTRY();
2119
2120         count = sprintf(buf, "%d\n", scst_global_threads_count());
2121
2122         TRACE_EXIT();
2123         return count;
2124 }
2125
2126 static ssize_t scst_threads_store(struct kobject *kobj,
2127         struct kobj_attribute *attr, const char *buf, size_t count)
2128 {
2129         int res = count;
2130         int oldtn, newtn, delta;
2131
2132         TRACE_ENTRY();
2133
2134         if (mutex_lock_interruptible(&scst_sysfs_mutex) != 0) {
2135                 res = -EINTR;
2136                 goto out;
2137         }
2138
2139         mutex_lock(&scst_global_threads_mutex);
2140
2141         oldtn = scst_nr_global_threads;
2142         sscanf(buf, "%du", &newtn);
2143
2144         if (newtn <= 0) {
2145                 PRINT_ERROR("Illegal threads num value %d", newtn);
2146                 res = -EINVAL;
2147                 goto out_up_thr_free;
2148         }
2149         delta = newtn - oldtn;
2150         if (delta < 0)
2151                 __scst_del_global_threads(-delta);
2152         else
2153                 __scst_add_global_threads(delta);
2154
2155         PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
2156
2157 out_up_thr_free:
2158         mutex_unlock(&scst_global_threads_mutex);
2159
2160         mutex_unlock(&scst_sysfs_mutex);
2161
2162 out:
2163         TRACE_EXIT_RES(res);
2164         return res;
2165 }
2166
2167 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2168
2169 static void scst_read_trace_tlb(const struct scst_trace_log *tbl, char *buf,
2170         unsigned long log_level, int *pos)
2171 {
2172         const struct scst_trace_log *t = tbl;
2173
2174         if (t == NULL)
2175                 goto out;
2176
2177         while (t->token) {
2178                 if (log_level & t->val) {
2179                         *pos += sprintf(&buf[*pos], "%s%s",
2180                                         (*pos == 0) ? "" : " | ",
2181                                         t->token);
2182                 }
2183                 t++;
2184         }
2185 out:
2186         return;
2187 }
2188
2189 static ssize_t scst_trace_level_show(const struct scst_trace_log *local_tbl,
2190         unsigned long log_level, char *buf, const char *help)
2191 {
2192         int pos = 0;
2193
2194         scst_read_trace_tlb(scst_trace_tbl, buf, log_level, &pos);
2195         scst_read_trace_tlb(local_tbl, buf, log_level, &pos);
2196
2197         pos += sprintf(&buf[pos], "\n\n\nUsage:\n"
2198                 "       echo \"all|none|default\" >trace_level\n"
2199                 "       echo \"value DEC|0xHEX|0OCT\" >trace_level\n"
2200                 "       echo \"add|del TOKEN\" >trace_level\n"
2201                 "\nwhere TOKEN is one of [debug, function, line, pid,\n"
2202 #ifndef GENERATING_UPSTREAM_PATCH
2203                 "                      entryexit, buff, mem, sg, out_of_mem,\n"
2204 #else
2205                 "                      buff, mem, sg, out_of_mem,\n"
2206 #endif
2207                 "                      special, scsi, mgmt, minor,\n"
2208                 "                      mgmt_minor, mgmt_dbg, scsi_serializing,\n"
2209                 "                      retry, recv_bot, send_bot, recv_top,\n"
2210                 "                      send_top%s]", help != NULL ? help : "");
2211
2212         return pos;
2213 }
2214
2215 static ssize_t scst_main_trace_level_show(struct kobject *kobj,
2216         struct kobj_attribute *attr, char *buf)
2217 {
2218         return scst_trace_level_show(scst_local_trace_tbl, trace_flag,
2219                         buf, NULL);
2220 }
2221
2222 static int scst_write_trace(const char *buf, size_t length,
2223         unsigned long *log_level, unsigned long default_level,
2224         const char *name, const struct scst_trace_log *tbl)
2225 {
2226         int res = length;
2227         int action;
2228         unsigned long level = 0, oldlevel;
2229         char *buffer, *p, *e;
2230         const struct scst_trace_log *t;
2231
2232 #define SCST_TRACE_ACTION_ALL           1
2233 #define SCST_TRACE_ACTION_NONE          2
2234 #define SCST_TRACE_ACTION_DEFAULT       3
2235 #define SCST_TRACE_ACTION_ADD           4
2236 #define SCST_TRACE_ACTION_DEL           5
2237 #define SCST_TRACE_ACTION_VALUE         6
2238
2239         TRACE_ENTRY();
2240
2241         if ((buf == NULL) || (length == 0)) {
2242                 res = -EINVAL;
2243                 goto out;
2244         }
2245
2246         buffer = kmalloc(length+1, GFP_KERNEL);
2247         if (buffer == NULL) {
2248                 PRINT_ERROR("Unable to alloc intermediate buffer (size %zd)",
2249                         length+1);
2250                 res = -ENOMEM;
2251                 goto out;
2252         }
2253         memcpy(buffer, buf, length);
2254         buffer[length] = '\0';
2255
2256         p = buffer;
2257         if (!strncasecmp("all", p, 3)) {
2258                 action = SCST_TRACE_ACTION_ALL;
2259         } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) {
2260                 action = SCST_TRACE_ACTION_NONE;
2261         } else if (!strncasecmp("default", p, 7)) {
2262                 action = SCST_TRACE_ACTION_DEFAULT;
2263         } else if (!strncasecmp("add", p, 3)) {
2264                 p += 3;
2265                 action = SCST_TRACE_ACTION_ADD;
2266         } else if (!strncasecmp("del", p, 3)) {
2267                 p += 3;
2268                 action = SCST_TRACE_ACTION_DEL;
2269         } else if (!strncasecmp("value", p, 5)) {
2270                 p += 5;
2271                 action = SCST_TRACE_ACTION_VALUE;
2272         } else {
2273                 if (p[strlen(p) - 1] == '\n')
2274                         p[strlen(p) - 1] = '\0';
2275                 PRINT_ERROR("Unknown action \"%s\"", p);
2276                 res = -EINVAL;
2277                 goto out_free;
2278         }
2279
2280         switch (action) {
2281         case SCST_TRACE_ACTION_ADD:
2282         case SCST_TRACE_ACTION_DEL:
2283         case SCST_TRACE_ACTION_VALUE:
2284                 if (!isspace(*p)) {
2285                         PRINT_ERROR("%s", "Syntax error");
2286                         res = -EINVAL;
2287                         goto out_free;
2288                 }
2289         }
2290
2291         switch (action) {
2292         case SCST_TRACE_ACTION_ALL:
2293                 level = TRACE_ALL;
2294                 break;
2295         case SCST_TRACE_ACTION_DEFAULT:
2296                 level = default_level;
2297                 break;
2298         case SCST_TRACE_ACTION_NONE:
2299                 level = TRACE_NULL;
2300                 break;
2301         case SCST_TRACE_ACTION_ADD:
2302         case SCST_TRACE_ACTION_DEL:
2303                 while (isspace(*p) && *p != '\0')
2304                         p++;
2305                 e = p;
2306                 while (!isspace(*e) && *e != '\0')
2307                         e++;
2308                 *e = 0;
2309                 if (tbl) {
2310                         t = tbl;
2311                         while (t->token) {
2312                                 if (!strcasecmp(p, t->token)) {
2313                                         level = t->val;
2314                                         break;
2315                                 }
2316                                 t++;
2317                         }
2318                 }
2319                 if (level == 0) {
2320                         t = scst_trace_tbl;
2321                         while (t->token) {
2322                                 if (!strcasecmp(p, t->token)) {
2323                                         level = t->val;
2324                                         break;
2325                                 }
2326                                 t++;
2327                         }
2328                 }
2329                 if (level == 0) {
2330                         PRINT_ERROR("Unknown token \"%s\"", p);
2331                         res = -EINVAL;
2332                         goto out_free;
2333                 }
2334                 break;
2335         case SCST_TRACE_ACTION_VALUE:
2336                 while (isspace(*p) && *p != '\0')
2337                         p++;
2338                 res = strict_strtoul(p, 0, &level);
2339                 if (res != 0) {
2340                         PRINT_ERROR("Invalid trace value \"%s\"", p);
2341                         res = -EINVAL;
2342                         goto out_free;
2343                 }
2344                 break;
2345         }
2346
2347         oldlevel = *log_level;
2348
2349         switch (action) {
2350         case SCST_TRACE_ACTION_ADD:
2351                 *log_level |= level;
2352                 break;
2353         case SCST_TRACE_ACTION_DEL:
2354                 *log_level &= ~level;
2355                 break;
2356         default:
2357                 *log_level = level;
2358                 break;
2359         }
2360
2361         PRINT_INFO("Changed trace level for \"%s\": old 0x%08lx, new 0x%08lx",
2362                 name, oldlevel, *log_level);
2363
2364 out_free:
2365         kfree(buffer);
2366 out:
2367         TRACE_EXIT_RES(res);
2368         return res;
2369
2370 #undef SCST_TRACE_ACTION_ALL
2371 #undef SCST_TRACE_ACTION_NONE
2372 #undef SCST_TRACE_ACTION_DEFAULT
2373 #undef SCST_TRACE_ACTION_ADD
2374 #undef SCST_TRACE_ACTION_DEL
2375 #undef SCST_TRACE_ACTION_VALUE
2376 }
2377
2378 static ssize_t scst_main_trace_level_store(struct kobject *kobj,
2379         struct kobj_attribute *attr, const char *buf, size_t count)
2380 {
2381         int res;
2382
2383         TRACE_ENTRY();
2384
2385         if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
2386                 res = -EINTR;
2387                 goto out;
2388         }
2389
2390         res = scst_write_trace(buf, count, &trace_flag,
2391                 SCST_DEFAULT_LOG_FLAGS, "scst", scst_local_trace_tbl);
2392
2393         mutex_unlock(&scst_log_mutex);
2394
2395 out:
2396         TRACE_EXIT_RES(res);
2397         return res;
2398 }
2399
2400 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
2401
2402 static ssize_t scst_version_show(struct kobject *kobj,
2403                                  struct kobj_attribute *attr,
2404                                  char *buf)
2405 {
2406         TRACE_ENTRY();
2407
2408         sprintf(buf, "%s\n", SCST_VERSION_STRING);
2409
2410 #ifdef CONFIG_SCST_STRICT_SERIALIZING
2411         strcat(buf, "Strict serializing enabled\n");
2412 #endif
2413
2414 #ifdef CONFIG_SCST_EXTRACHECKS
2415         strcat(buf, "EXTRACHECKS\n");
2416 #endif
2417
2418 #ifdef CONFIG_SCST_TRACING
2419         strcat(buf, "TRACING\n");
2420 #endif
2421
2422 #ifdef CONFIG_SCST_DEBUG
2423         strcat(buf, "DEBUG\n");
2424 #endif
2425
2426 #ifdef CONFIG_SCST_DEBUG_TM
2427         strcat(buf, "DEBUG_TM\n");
2428 #endif
2429
2430 #ifdef CONFIG_SCST_DEBUG_RETRY
2431         strcat(buf, "DEBUG_RETRY\n");
2432 #endif
2433
2434 #ifdef CONFIG_SCST_DEBUG_OOM
2435         strcat(buf, "DEBUG_OOM\n");
2436 #endif
2437
2438 #ifdef CONFIG_SCST_DEBUG_SN
2439         strcat(buf, "DEBUG_SN\n");
2440 #endif
2441
2442 #ifdef CONFIG_SCST_USE_EXPECTED_VALUES
2443         strcat(buf, "USE_EXPECTED_VALUES\n");
2444 #endif
2445
2446 #ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
2447         strcat(buf, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
2448 #endif
2449
2450 #ifdef CONFIG_SCST_STRICT_SECURITY
2451         strcat(buf, "SCST_STRICT_SECURITY\n");
2452 #endif
2453
2454         TRACE_EXIT();
2455         return strlen(buf);
2456 }
2457
2458 static struct kobj_attribute scst_threads_attr =
2459         __ATTR(threads, S_IRUGO | S_IWUSR, scst_threads_show,
2460                scst_threads_store);
2461
2462 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2463 static struct kobj_attribute scst_trace_level_attr =
2464         __ATTR(trace_level, S_IRUGO | S_IWUSR, scst_main_trace_level_show,
2465                scst_main_trace_level_store);
2466 #endif
2467
2468 static struct kobj_attribute scst_version_attr =
2469         __ATTR(version, S_IRUGO, scst_version_show, NULL);
2470
2471 static struct attribute *scst_sysfs_root_default_attrs[] = {
2472         &scst_threads_attr.attr,
2473 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2474         &scst_trace_level_attr.attr,
2475 #endif
2476         &scst_version_attr.attr,
2477         NULL,
2478 };
2479
2480 static void scst_sysfs_root_release(struct kobject *kobj)
2481 {
2482         complete_all(&scst_sysfs_root_release_completion);
2483 }
2484
2485 static ssize_t scst_show(struct kobject *kobj, struct attribute *attr,
2486                          char *buf)
2487 {
2488         struct kobj_attribute *kobj_attr;
2489         kobj_attr = container_of(attr, struct kobj_attribute, attr);
2490
2491         return kobj_attr->show(kobj, kobj_attr, buf);
2492 }
2493
2494 static ssize_t scst_store(struct kobject *kobj, struct attribute *attr,
2495                           const char *buf, size_t count)
2496 {
2497         struct kobj_attribute *kobj_attr;
2498         kobj_attr = container_of(attr, struct kobj_attribute, attr);
2499
2500         return kobj_attr->store(kobj, kobj_attr, buf, count);
2501 }
2502
2503 struct sysfs_ops scst_sysfs_ops = {
2504         .show = scst_show,
2505         .store = scst_store,
2506 };
2507
2508 static struct kobj_type scst_sysfs_root_ktype = {
2509         .sysfs_ops = &scst_sysfs_ops,
2510         .release = scst_sysfs_root_release,
2511         .default_attrs = scst_sysfs_root_default_attrs,
2512 };
2513
2514 static void scst_devt_free(struct kobject *kobj)
2515 {
2516         struct scst_dev_type *devt;
2517
2518         TRACE_ENTRY();
2519
2520         devt = container_of(kobj, struct scst_dev_type, devt_kobj);
2521
2522         complete_all(&devt->devt_kobj_release_compl);
2523
2524         scst_devt_cleanup(devt);
2525
2526         TRACE_EXIT();
2527         return;
2528 }
2529
2530 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2531
2532 static ssize_t scst_devt_trace_level_show(struct kobject *kobj,
2533         struct kobj_attribute *attr, char *buf)
2534 {
2535         struct scst_dev_type *devt;
2536
2537         devt = container_of(kobj, struct scst_dev_type, devt_kobj);
2538
2539         return scst_trace_level_show(devt->trace_tbl,
2540                 devt->trace_flags ? *devt->trace_flags : 0, buf,
2541                 devt->trace_tbl_help);
2542 }
2543
2544 static ssize_t scst_devt_trace_level_store(struct kobject *kobj,
2545         struct kobj_attribute *attr, const char *buf, size_t count)
2546 {
2547         int res;
2548         struct scst_dev_type *devt;
2549
2550         TRACE_ENTRY();
2551
2552         devt = container_of(kobj, struct scst_dev_type, devt_kobj);
2553
2554         if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
2555                 res = -EINTR;
2556                 goto out;
2557         }
2558
2559         res = scst_write_trace(buf, count, devt->trace_flags,
2560                 devt->default_trace_flags, devt->name, devt->trace_tbl);
2561
2562         mutex_unlock(&scst_log_mutex);
2563
2564 out:
2565         TRACE_EXIT_RES(res);
2566         return res;
2567 }
2568
2569 static struct kobj_attribute devt_trace_attr =
2570         __ATTR(trace_level, S_IRUGO | S_IWUSR,
2571                scst_devt_trace_level_show, scst_devt_trace_level_store);
2572
2573 #endif /* #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
2574
2575 static ssize_t scst_devt_type_show(struct kobject *kobj,
2576         struct kobj_attribute *attr, char *buf)
2577 {
2578         int pos;
2579         struct scst_dev_type *devt;
2580
2581         devt = container_of(kobj, struct scst_dev_type, devt_kobj);
2582
2583         pos = sprintf(buf, "%d - %s\n", devt->type,
2584                 (unsigned)devt->type > ARRAY_SIZE(scst_dev_handler_types) ?
2585                         "unknown" : scst_dev_handler_types[devt->type]);
2586
2587         return pos;
2588 }
2589
2590 static struct kobj_attribute scst_devt_type_attr =
2591         __ATTR(type, S_IRUGO, scst_devt_type_show, NULL);
2592
2593 static struct attribute *scst_devt_default_attrs[] = {
2594         &scst_devt_type_attr.attr,
2595         NULL,
2596 };
2597
2598 static struct kobj_type scst_devt_ktype = {
2599         .sysfs_ops = &scst_sysfs_ops,
2600         .release = scst_devt_free,
2601         .default_attrs = scst_devt_default_attrs,
2602 };
2603
2604 int scst_create_devt_sysfs(struct scst_dev_type *devt)
2605 {
2606         int retval;
2607         struct kobject *parent;
2608         const struct attribute **pattr;
2609
2610         TRACE_ENTRY();
2611
2612         init_completion(&devt->devt_kobj_release_compl);
2613
2614         if (devt->parent != NULL)
2615                 parent = &devt->parent->devt_kobj;
2616         else
2617                 parent = scst_handlers_kobj;
2618
2619         devt->devt_kobj_initialized = 1;
2620
2621         retval = kobject_init_and_add(&devt->devt_kobj, &scst_devt_ktype,
2622                         parent, devt->name);
2623         if (retval != 0) {
2624                 PRINT_ERROR("Can't add devt %s to sysfs", devt->name);
2625                 goto out;
2626         }
2627
2628         /*
2629          * In case of errors there's no need for additional cleanup, because
2630          * it will be done by the _put function() called by the caller.
2631          */
2632
2633         pattr = devt->devt_attrs;
2634         if (pattr != NULL) {
2635                 while (*pattr != NULL) {
2636                         retval = sysfs_create_file(&devt->devt_kobj, *pattr);
2637                         if (retval != 0) {
2638                                 PRINT_ERROR("Can't add devt attr %s for dev "
2639                                         "handler %s", (*pattr)->name,
2640                                         devt->name);
2641                                 goto out;
2642                         }
2643                         pattr++;
2644                 }
2645         }
2646
2647 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
2648         if (devt->trace_flags != NULL) {
2649                 retval = sysfs_create_file(&devt->devt_kobj,
2650                                 &devt_trace_attr.attr);
2651                 if (retval != 0) {
2652                         PRINT_ERROR("Can't add devt trace_flag for dev "
2653                                 "handler %s", devt->name);
2654                         goto out;
2655                 }
2656         }
2657 #endif
2658
2659 out:
2660         TRACE_EXIT_RES(retval);
2661         return retval;
2662 }
2663
2664 void scst_devt_sysfs_put(struct scst_dev_type *devt)
2665 {
2666         TRACE_ENTRY();
2667
2668         if (devt->devt_kobj_initialized) {
2669                 int rc;
2670
2671                 kobject_del(&devt->devt_kobj);
2672                 kobject_put(&devt->devt_kobj);
2673
2674                 rc = wait_for_completion_timeout(&devt->devt_kobj_release_compl, HZ);
2675                 if (rc == 0) {
2676                         PRINT_INFO("Waiting for releasing sysfs entry "
2677                                 "for dev handler template %s...", devt->name);
2678                         wait_for_completion(&devt->devt_kobj_release_compl);
2679                         PRINT_INFO("Done waiting for releasing sysfs entry "
2680                                 "for dev handler template %s", devt->name);
2681                 }
2682         } else
2683                 scst_devt_cleanup(devt);
2684
2685         TRACE_EXIT();
2686         return;
2687 }
2688
2689 int __init scst_sysfs_init(void)
2690 {
2691         int retval = 0;
2692
2693         TRACE_ENTRY();
2694
2695         retval = kobject_init_and_add(&scst_sysfs_root_kobj,
2696                         &scst_sysfs_root_ktype, kernel_kobj, "%s", "scst_tgt");
2697         if (retval != 0)
2698                 goto sysfs_root_add_error;
2699
2700         scst_targets_kobj = kobject_create_and_add("targets",
2701                                 &scst_sysfs_root_kobj);
2702         if (scst_targets_kobj == NULL)
2703                 goto targets_kobj_error;
2704
2705         scst_devices_kobj = kobject_create_and_add("devices",
2706                                 &scst_sysfs_root_kobj);
2707         if (scst_devices_kobj == NULL)
2708                 goto devices_kobj_error;
2709
2710         scst_sgv_kobj = kzalloc(sizeof(*scst_sgv_kobj), GFP_KERNEL);
2711         if (scst_sgv_kobj == NULL)
2712                 goto sgv_kobj_error;
2713
2714         retval = kobject_init_and_add(scst_sgv_kobj, &sgv_ktype,
2715                         &scst_sysfs_root_kobj, "%s", "sgv");
2716         if (retval != 0)
2717                 goto sgv_kobj_add_error;
2718
2719         scst_handlers_kobj = kobject_create_and_add("handlers",
2720                                         &scst_sysfs_root_kobj);
2721         if (scst_handlers_kobj == NULL)
2722                 goto handlers_kobj_error;
2723
2724 out:
2725         TRACE_EXIT_RES(retval);
2726         return retval;
2727
2728 handlers_kobj_error:
2729         kobject_del(scst_sgv_kobj);
2730
2731 sgv_kobj_add_error:
2732         kobject_put(scst_sgv_kobj);
2733
2734 sgv_kobj_error:
2735         kobject_del(scst_devices_kobj);
2736         kobject_put(scst_devices_kobj);
2737
2738 devices_kobj_error:
2739         kobject_del(scst_targets_kobj);
2740         kobject_put(scst_targets_kobj);
2741
2742 targets_kobj_error:
2743         kobject_del(&scst_sysfs_root_kobj);
2744
2745 sysfs_root_add_error:
2746         kobject_put(&scst_sysfs_root_kobj);
2747
2748         if (retval == 0)
2749                 retval = -EINVAL;
2750         goto out;
2751 }
2752
2753 void scst_sysfs_cleanup(void)
2754 {
2755         TRACE_ENTRY();
2756
2757         PRINT_INFO("%s", "Exiting SCST sysfs hierarchy...");
2758
2759         kobject_del(scst_sgv_kobj);
2760         kobject_put(scst_sgv_kobj);
2761
2762         kobject_del(scst_devices_kobj);
2763         kobject_put(scst_devices_kobj);
2764
2765         kobject_del(scst_targets_kobj);
2766         kobject_put(scst_targets_kobj);
2767
2768         kobject_del(scst_handlers_kobj);
2769         kobject_put(scst_handlers_kobj);
2770
2771         kobject_del(&scst_sysfs_root_kobj);
2772         kobject_put(&scst_sysfs_root_kobj);
2773
2774         wait_for_completion(&scst_sysfs_root_release_completion);
2775         /*
2776          * There is a race, when in the release() schedule happens just after
2777          * calling complete(), so if we exit and unload scst module immediately,
2778          * there will be oops there. So let's give it a chance to quit
2779          * gracefully. Unfortunately, current kobjects implementation
2780          * doesn't allow better ways to handle it.
2781          */
2782         msleep(3000);
2783
2784         PRINT_INFO("%s", "Exiting SCST sysfs hierarchy done");
2785
2786         TRACE_EXIT();
2787         return;
2788 }