57aadd4f0d01cfa0c4b205af257bb3c09f82df90
[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 static struct sysfs_ops scst_sysfs_ops;
41
42 static const char *scst_dev_handler_types[] =
43 {
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 {
68     { TRACE_OUT_OF_MEM,         "out_of_mem" },
69     { TRACE_MINOR,              "minor" },
70     { TRACE_SG_OP,              "sg" },
71     { TRACE_MEMORY,             "mem" },
72     { TRACE_BUFF,               "buff" },
73     { TRACE_ENTRYEXIT,          "entryexit" },
74     { TRACE_PID,                "pid" },
75     { TRACE_LINE,               "line" },
76     { TRACE_FUNCTION,           "function" },
77     { TRACE_DEBUG,              "debug" },
78     { TRACE_SPECIAL,            "special" },
79     { TRACE_SCSI,               "scsi" },
80     { TRACE_MGMT,               "mgmt" },
81     { TRACE_MGMT_MINOR,         "mgmt_minor" },
82     { TRACE_MGMT_DEBUG,         "mgmt_dbg" },
83     { 0,                        NULL }
84 };
85
86 static struct scst_trace_log scst_local_trace_tbl[] =
87 {
88     { TRACE_RTRY,               "retry" },
89     { TRACE_SCSI_SERIALIZING,   "scsi_serializing" },
90     { TRACE_RCV_BOT,            "recv_bot" },
91     { TRACE_SND_BOT,            "send_bot" },
92     { TRACE_RCV_TOP,            "recv_top" },
93     { TRACE_SND_TOP,            "send_top" },
94     { 0,                        NULL }
95 };
96
97 static ssize_t scst_trace_level_show(const struct scst_trace_log *local_tbl,
98         unsigned long log_level, char *buf, const char *help);
99 static int scst_write_trace(const char *buf, size_t length,
100         unsigned long *log_level, unsigned long default_level,
101         const char *name, const struct scst_trace_log *tbl);
102
103 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
104
105 static ssize_t scst_luns_mgmt_show(struct kobject *kobj,
106                                    struct kobj_attribute *attr,
107                                    char *buf);
108 static ssize_t scst_luns_mgmt_store(struct kobject *kobj,
109                                     struct kobj_attribute *attr,
110                                     const char *buf, size_t count);
111
112 static void scst_sysfs_release(struct kobject *kobj)
113 {
114         kfree(kobj);
115 }
116
117 /*
118  * Target Template
119  */
120
121 static void scst_tgtt_release(struct kobject *kobj)
122 {
123         struct scst_tgt_template *tgtt;
124
125         TRACE_ENTRY();
126
127         tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
128
129         complete_all(&tgtt->tgtt_kobj_release_cmpl);
130
131         scst_tgtt_cleanup(tgtt);
132
133         TRACE_EXIT();
134         return;
135 }
136
137 static struct kobj_type tgtt_ktype = {
138         .sysfs_ops = &scst_sysfs_ops,
139         .release = scst_tgtt_release,
140 };
141
142 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
143
144 static ssize_t scst_tgtt_trace_level_show(struct kobject *kobj,
145         struct kobj_attribute *attr, char *buf)
146 {
147         struct scst_tgt_template *tgtt;
148
149         tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
150
151         return scst_trace_level_show(tgtt->trace_tbl,
152                 tgtt->trace_flags ? *tgtt->trace_flags : 0, buf,
153                 tgtt->trace_tbl_help);
154 }
155
156 static ssize_t scst_tgtt_trace_level_store(struct kobject *kobj,
157         struct kobj_attribute *attr, const char *buf, size_t count)
158 {
159         int res;
160         struct scst_tgt_template *tgtt;
161
162         TRACE_ENTRY();
163
164         tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
165
166         if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
167                 res = -EINTR;
168                 goto out;
169         }
170
171         res = scst_write_trace(buf, count, tgtt->trace_flags,
172                 tgtt->default_trace_flags, tgtt->name, tgtt->trace_tbl);
173
174         mutex_unlock(&scst_log_mutex);
175
176 out:
177         TRACE_EXIT_RES(res);
178         return res;
179 }
180
181 static struct kobj_attribute tgtt_trace_attr =
182         __ATTR(trace_level, S_IRUGO | S_IWUSR,
183                scst_tgtt_trace_level_show, scst_tgtt_trace_level_store);
184
185 #endif /* #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
186
187 int scst_create_tgtt_sysfs(struct scst_tgt_template *tgtt)
188 {
189         int retval = 0;
190         const struct attribute **pattr;
191
192         TRACE_ENTRY();
193
194         init_completion(&tgtt->tgtt_kobj_release_cmpl);
195
196         tgtt->tgtt_kobj_initialized = 1;
197
198         retval = kobject_init_and_add(&tgtt->tgtt_kobj, &tgtt_ktype,
199                         scst_targets_kobj, tgtt->name);
200         if (retval != 0) {
201                 PRINT_ERROR("Can't add tgtt %s to sysfs", tgtt->name);
202                 goto out;
203         }
204
205         /*
206          * In case of errors there's no need for additional cleanup, because
207          * it will be done by the _put function() called by the caller.
208          */
209
210         pattr = tgtt->tgtt_attrs;
211         if (pattr != NULL) {
212                 while (*pattr != NULL) {
213                         TRACE_DBG("Creating attr %s for target driver %s",
214                                 (*pattr)->name, tgtt->name);
215                         retval = sysfs_create_file(&tgtt->tgtt_kobj, *pattr);
216                         if (retval != 0) {
217                                 PRINT_ERROR("Can't add attr %s for target "
218                                         "driver %s", (*pattr)->name,
219                                         tgtt->name);
220                                 goto out;
221                         }
222                         pattr++;
223                 }
224         }
225
226 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
227         if (tgtt->trace_flags != NULL) {
228                 retval = sysfs_create_file(&tgtt->tgtt_kobj,
229                                 &tgtt_trace_attr.attr);
230                 if (retval != 0) {
231                         PRINT_ERROR("Can't add trace_flag for target "
232                                 "driver %s", tgtt->name);
233                         goto out;
234                 }
235         }
236 #endif
237
238 out:
239         TRACE_EXIT_RES(retval);
240         return retval;
241 }
242
243 void scst_tgtt_sysfs_put(struct scst_tgt_template *tgtt)
244 {
245         TRACE_ENTRY();
246
247         if (tgtt->tgtt_kobj_initialized) {
248                 int rc;
249
250                 kobject_del(&tgtt->tgtt_kobj);
251                 kobject_put(&tgtt->tgtt_kobj);
252
253                 rc = wait_for_completion_timeout(&tgtt->tgtt_kobj_release_cmpl, HZ);
254                 if (rc == 0) {
255                         PRINT_INFO("Waiting for releasing sysfs entry "
256                                 "for target template %s...", tgtt->name);
257                         wait_for_completion(&tgtt->tgtt_kobj_release_cmpl);
258                         PRINT_INFO("Done waiting for releasing sysfs "
259                                 "entry for target template %s", tgtt->name);
260                 }
261         } else
262                 scst_tgtt_cleanup(tgtt);
263
264         TRACE_EXIT();
265         return;
266 }
267
268 /*
269  * Target directory implementation
270  */
271
272 static void scst_tgt_release(struct kobject *kobj)
273 {
274         struct scst_tgt *tgt;
275
276         TRACE_ENTRY();
277
278         tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
279
280         scst_free_tgt(tgt);
281
282         TRACE_EXIT();
283         return;
284 }
285
286 static struct kobj_type tgt_ktype = {
287         .sysfs_ops = &scst_sysfs_ops,
288         .release = scst_tgt_release,
289 };
290
291 static struct kobj_attribute scst_luns_mgmt =
292         __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_luns_mgmt_show,
293                scst_luns_mgmt_store);
294
295 static ssize_t scst_tgt_enable_show(struct kobject *kobj,
296         struct kobj_attribute *attr, char *buf)
297 {
298         struct scst_tgt *tgt;
299         int res;
300         bool enabled;
301
302         TRACE_ENTRY();
303
304         tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
305
306         enabled = tgt->tgtt->is_tgt_enabled(tgt);
307
308         res = sprintf(buf, "%d\n", enabled ? 1 : 0);
309
310         TRACE_EXIT_RES(res);
311         return res;
312 }
313
314 static ssize_t scst_tgt_enable_store(struct kobject *kobj,
315         struct kobj_attribute *attr, const char *buf, size_t count)
316 {
317         int res;
318         struct scst_tgt *tgt;
319
320         TRACE_ENTRY();
321
322         if (buf == NULL)
323                 goto out_err;
324
325         tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
326
327         res = tgt->tgtt->enable_tgt(tgt, buf, count);
328
329 out:
330         TRACE_EXIT_RES(res);
331         return res;
332
333 out_err:
334         PRINT_ERROR("%s: Requested action not understood: %s", __func__, buf);
335         res = -EINVAL;
336         goto out;
337 }
338
339 static struct kobj_attribute tgt_enable_attr =
340         __ATTR(enabled, S_IRUGO | S_IWUSR,
341                scst_tgt_enable_show, scst_tgt_enable_store);
342
343 int scst_create_tgt_sysfs(struct scst_tgt *tgt)
344 {
345         int retval;
346         const struct attribute **pattr;
347
348         TRACE_ENTRY();
349
350         tgt->tgt_kobj_initialized = 1;
351
352         retval = kobject_init_and_add(&tgt->tgt_kobj, &tgt_ktype,
353                         &tgt->tgtt->tgtt_kobj, tgt->tgt_name);
354         if (retval != 0) {
355                 PRINT_ERROR("Can't add tgt %s to sysfs", tgt->tgt_name);
356                 goto out;
357         }
358
359         /*
360          * In case of errors there's no need for additional cleanup, because
361          * it will be done by the _put function() called by the caller.
362          */
363
364         if ((tgt->tgtt->enable_tgt != NULL) &&
365             (tgt->tgtt->is_tgt_enabled != NULL)) {
366                 retval = sysfs_create_file(&tgt->tgt_kobj,
367                                 &tgt_enable_attr.attr);
368                 if (retval != 0) {
369                         PRINT_ERROR("Can't add attr %s to sysfs",
370                                 tgt_enable_attr.attr.name);
371                         goto out;
372                 }
373         }
374
375         tgt->tgt_sess_kobj = kobject_create_and_add("sessions", &tgt->tgt_kobj);
376         if (tgt->tgt_sess_kobj == NULL) {
377                 PRINT_ERROR("Can't create sess kobj for tgt %s", tgt->tgt_name);
378                 goto out_nomem;
379         }
380
381         tgt->tgt_luns_kobj = kobject_create_and_add("luns", &tgt->tgt_kobj);
382         if (tgt->tgt_luns_kobj == NULL) {
383                 PRINT_ERROR("Can't create luns kobj for tgt %s", tgt->tgt_name);
384                 goto out_nomem;
385         }
386
387         retval = sysfs_create_file(tgt->tgt_luns_kobj, &scst_luns_mgmt.attr);
388         if (retval != 0) {
389                 PRINT_ERROR("Can't add tgt attr %s for tgt %s",
390                         scst_luns_mgmt.attr.name, tgt->tgt_name);
391                 goto out;
392         }
393
394         tgt->tgt_ini_grp_kobj = kobject_create_and_add("ini_group",
395                                         &tgt->tgt_kobj);
396         if (tgt->tgt_ini_grp_kobj == NULL) {
397                 PRINT_ERROR("Can't create ini_grp kobj for tgt %s",
398                         tgt->tgt_name);
399                 goto out_nomem;
400         }
401
402         pattr = tgt->tgtt->tgt_attrs;
403         if (pattr != NULL) {
404                 while (*pattr != NULL) {
405                         TRACE_DBG("Creating attr %s for tgt %s", (*pattr)->name,
406                                 tgt->tgt_name);
407                         retval = sysfs_create_file(&tgt->tgt_kobj, *pattr);
408                         if (retval != 0) {
409                                 PRINT_ERROR("Can't add tgt attr %s for tgt %s",
410                                         (*pattr)->name, tgt->tgt_name);
411                                 goto out;
412                         }
413                         pattr++;
414                 }
415         }
416
417 out:
418         TRACE_EXIT_RES(retval);
419         return retval;
420
421 out_nomem:
422         retval = -ENOMEM;
423         goto out;
424 }
425
426 void scst_tgt_sysfs_put(struct scst_tgt *tgt)
427 {
428         if (tgt->tgt_kobj_initialized) {
429                 kobject_del(tgt->tgt_sess_kobj);
430                 kobject_put(tgt->tgt_sess_kobj);
431
432                 sysfs_remove_file(tgt->tgt_luns_kobj, &scst_luns_mgmt.attr);
433
434                 kobject_del(tgt->tgt_luns_kobj);
435                 kobject_put(tgt->tgt_luns_kobj);
436
437                 kobject_del(tgt->tgt_ini_grp_kobj);
438                 kobject_put(tgt->tgt_ini_grp_kobj);
439
440                 kobject_del(&tgt->tgt_kobj);
441                 kobject_put(&tgt->tgt_kobj);
442         } else
443                 scst_free_tgt(tgt);
444         return;
445 }
446
447 /*
448  * Devices directory implementation
449  */
450
451 ssize_t scst_device_sysfs_type_show(struct kobject *kobj,
452                             struct kobj_attribute *attr, char *buf)
453 {
454         int pos = 0;
455
456         struct scst_device *dev;
457
458         dev = container_of(kobj, struct scst_device, dev_kobj);
459
460         pos = sprintf(buf, "%d - %s\n", dev->type,
461                 (unsigned)dev->type > ARRAY_SIZE(scst_dev_handler_types) ?
462                       "unknown" : scst_dev_handler_types[dev->type]);
463
464         return pos;
465 }
466
467 static struct kobj_attribute device_type_attr =
468         __ATTR(type, S_IRUGO, scst_device_sysfs_type_show, NULL);
469
470 static struct attribute *scst_device_attrs[] = {
471         &device_type_attr.attr,
472         NULL,
473 };
474
475 static void scst_sysfs_device_release(struct kobject *kobj)
476 {
477         struct scst_device *dev;
478
479         TRACE_ENTRY();
480
481         dev = container_of(kobj, struct scst_device, dev_kobj);
482
483         scst_free_device(dev);
484
485         TRACE_EXIT();
486         return;
487 }
488
489 int scst_create_devt_dev_sysfs(struct scst_device *dev)
490 {
491         int retval = 0;
492         const struct attribute **pattr;
493
494         TRACE_ENTRY();
495
496         if (dev->handler == &scst_null_devtype)
497                 goto out;
498
499         sBUG_ON(!dev->handler->devt_kobj_initialized);
500
501         /*
502          * In case of errors there's no need for additional cleanup, because
503          * it will be done by the _put function() called by the caller.
504          */
505
506         retval = sysfs_create_link(&dev->dev_kobj,
507                         &dev->handler->devt_kobj, "handler");
508         if (retval != 0) {
509                 PRINT_ERROR("Can't create handler link for dev %s",
510                         dev->virt_name);
511                 goto out;
512         }
513
514         pattr = dev->handler->dev_attrs;
515         if (pattr != NULL) {
516                 while (*pattr != NULL) {
517                         retval = sysfs_create_file(&dev->dev_kobj, *pattr);
518                         if (retval != 0) {
519                                 PRINT_ERROR("Can't add dev attr %s for dev %s",
520                                         (*pattr)->name, dev->virt_name);
521                                 goto out;
522                         }
523                         pattr++;
524                 }
525         }
526
527 out:
528         TRACE_EXIT_RES(retval);
529         return retval;
530 }
531
532 void scst_devt_dev_sysfs_put(struct scst_device *dev)
533 {
534         const struct attribute **pattr;
535
536         TRACE_ENTRY();
537
538         if (dev->handler == &scst_null_devtype)
539                 goto out;
540
541         sBUG_ON(!dev->handler->devt_kobj_initialized);
542
543         pattr = dev->handler->dev_attrs;
544         if (pattr != NULL) {
545                 while (*pattr != NULL) {
546                         sysfs_remove_file(&dev->dev_kobj, *pattr);
547                         pattr++;
548                 }
549         }
550
551         sysfs_remove_link(&dev->dev_kobj, "handler");
552
553 out:
554         TRACE_EXIT();
555         return;
556 }
557
558 static struct kobj_type scst_device_ktype = {
559         .sysfs_ops = &scst_sysfs_ops,
560         .release = scst_sysfs_device_release,
561         .default_attrs = scst_device_attrs,
562 };
563
564 int scst_create_device_sysfs(struct scst_device *dev)
565 {
566         int retval = 0;
567
568         TRACE_ENTRY();
569
570         dev->dev_kobj_initialized = 1;
571
572         retval = kobject_init_and_add(&dev->dev_kobj, &scst_device_ktype,
573                                       scst_devices_kobj, dev->virt_name);
574         if (retval != 0) {
575                 PRINT_ERROR("Can't add device %s to sysfs", dev->virt_name);
576                 goto out;
577         }
578
579         /*
580          * In case of errors there's no need for additional cleanup, because
581          * it will be done by the _put function() called by the caller.
582          */
583
584         dev->dev_exp_kobj = kobject_create_and_add("exported",
585                                                    &dev->dev_kobj);
586         if (dev->dev_exp_kobj == NULL) {
587                 PRINT_ERROR("Can't create exported link for device %s",
588                         dev->virt_name);
589                 retval = -ENOMEM;
590                 goto out;
591         }
592
593         if (dev->scsi_dev != NULL) {
594                 retval = sysfs_create_link(&dev->dev_kobj,
595                         &dev->scsi_dev->sdev_dev.kobj, "scsi_device");
596                 if (retval != 0) {
597                         PRINT_ERROR("Can't create scsi_device link for dev %s",
598                                 dev->virt_name);
599                         goto out;
600                 }
601         }
602
603 out:
604         TRACE_EXIT_RES(retval);
605         return retval;
606 }
607
608 void scst_device_sysfs_put(struct scst_device *dev)
609 {
610         TRACE_ENTRY();
611
612         if (dev->dev_kobj_initialized) {
613                 if (dev->dev_exp_kobj != NULL) {
614                         kobject_del(dev->dev_exp_kobj);
615                         kobject_put(dev->dev_exp_kobj);
616                 }
617                 kobject_del(&dev->dev_kobj);
618                 kobject_put(&dev->dev_kobj);
619         } else
620                 scst_free_device(dev);
621
622         TRACE_EXIT();
623         return;
624 }
625
626 /*
627  * Target sessions directory implementation
628  */
629
630 ssize_t scst_sess_sysfs_commands_show(struct kobject *kobj,
631                             struct kobj_attribute *attr, char *buf)
632 {
633         struct scst_session *sess;
634
635         sess = container_of(kobj, struct scst_session, sess_kobj);
636
637         return sprintf(buf, "%i\n", atomic_read(&sess->sess_cmd_count));
638 }
639
640 static struct kobj_attribute session_commands_attr =
641         __ATTR(commands, S_IRUGO, scst_sess_sysfs_commands_show, NULL);
642
643 static struct attribute *scst_session_attrs[] = {
644         &session_commands_attr.attr,
645         NULL,
646 };
647
648 static void scst_sysfs_session_release(struct kobject *kobj)
649 {
650         struct scst_session *sess;
651
652         TRACE_ENTRY();
653
654         sess = container_of(kobj, struct scst_session, sess_kobj);
655
656         scst_release_session(sess);
657
658         TRACE_EXIT();
659         return;
660 }
661
662 static struct kobj_type scst_session_ktype = {
663         .sysfs_ops = &scst_sysfs_ops,
664         .release = scst_sysfs_session_release,
665         .default_attrs = scst_session_attrs,
666 };
667
668 int scst_create_sess_sysfs(struct scst_session *sess)
669 {
670         int retval = 0;
671
672         TRACE_ENTRY();
673
674         sess->sess_kobj_initialized = 1;
675
676         retval = kobject_init_and_add(&sess->sess_kobj, &scst_session_ktype,
677                               sess->tgt->tgt_sess_kobj, sess->initiator_name);
678         if (retval != 0) {
679                 PRINT_ERROR("Can't add session %s to sysfs",
680                             sess->initiator_name);
681                 goto out;
682         }
683
684         /*
685          * In case of errors there's no need for additional cleanup, because
686          * it will be done by the _put function() called by the caller.
687          */
688
689 out:
690         TRACE_EXIT_RES(retval);
691         return retval;
692 }
693
694 void scst_sess_sysfs_put(struct scst_session *sess)
695 {
696         TRACE_ENTRY();
697
698         if (sess->sess_kobj_initialized) {
699                 kobject_del(&sess->sess_kobj);
700                 kobject_put(&sess->sess_kobj);
701         } else
702                 scst_release_session(sess);
703
704         TRACE_EXIT();
705         return;
706 }
707
708 /*
709  * Target luns directory implementation
710  */
711
712 static void scst_acg_dev_release(struct kobject *kobj)
713 {
714         struct scst_acg_dev *acg_dev;
715
716         TRACE_ENTRY();
717
718         acg_dev = container_of(kobj, struct scst_acg_dev, acg_dev_kobj);
719
720         scst_acg_dev_destroy(acg_dev);
721
722         TRACE_EXIT();
723         return;
724 }
725
726 static ssize_t scst_lun_rd_only_show(struct kobject *kobj,
727                                    struct kobj_attribute *attr,
728                                    char *buf)
729 {
730         struct scst_acg_dev *acg_dev;
731
732         acg_dev = container_of(kobj, struct scst_acg_dev, acg_dev_kobj);
733
734         return sprintf(buf, "%d\n",
735                 (acg_dev->rd_only || acg_dev->dev->rd_only) ? 1 : 0);
736 }
737
738 static struct kobj_attribute lun_options_attr =
739         __ATTR(read_only, S_IRUGO, scst_lun_rd_only_show, NULL);
740
741 static struct attribute *lun_attrs[] = {
742         &lun_options_attr.attr,
743         NULL,
744 };
745
746 static struct kobj_type acg_dev_ktype = {
747         .sysfs_ops = &scst_sysfs_ops,
748         .release = scst_acg_dev_release,
749         .default_attrs = lun_attrs,
750 };
751
752 int scst_create_acg_dev_sysfs(struct scst_acg *acg, unsigned int virt_lun,
753         struct kobject *parent)
754 {
755         int retval;
756         struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
757         char str[10];
758
759         TRACE_ENTRY();
760
761         list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
762                             acg_dev_list_entry) {
763                 if (acg_dev_tmp->lun == virt_lun) {
764                         acg_dev = acg_dev_tmp;
765                         break;
766                 }
767         }
768         if (acg_dev == NULL) {
769                 PRINT_ERROR("%s", "acg_dev lookup for kobject creation failed");
770                 retval = -EINVAL;
771                 goto out;
772         }
773
774         snprintf(str, sizeof(str), "%u", acg_dev->dev->dev_exported_lun_num++);
775
776         acg_dev->acg_dev_kobj_initialized = 1;
777
778         retval = kobject_init_and_add(&acg_dev->acg_dev_kobj, &acg_dev_ktype,
779                                       parent, "%u", virt_lun);
780         if (retval != 0) {
781                 PRINT_ERROR("Can't add acg %s to sysfs", acg->acg_name);
782                 goto out;
783         }
784
785         /*
786          * In case of errors there's no need for additional cleanup, because
787          * it will be done by the _put function() called by the caller.
788          */
789
790         retval = sysfs_create_link(acg_dev->dev->dev_exp_kobj,
791                                    &acg_dev->acg_dev_kobj, str);
792         if (retval != 0) {
793                 PRINT_ERROR("Can't create acg %s LUN link", acg->acg_name);
794                 goto out;
795         }
796
797         retval = sysfs_create_link(&acg_dev->acg_dev_kobj,
798                         &acg_dev->dev->dev_kobj, "device");
799         if (retval != 0) {
800                 PRINT_ERROR("Can't create acg %s device link", acg->acg_name);
801                 goto out;
802         }
803
804 out:
805         return retval;
806 }
807
808 static ssize_t scst_luns_mgmt_show(struct kobject *kobj,
809                                    struct kobj_attribute *attr,
810                                    char *buf)
811 {
812         static char *help = "Usage: echo \"add|del H:C:I:L lun [READ_ONLY]\" "
813                                         ">mgmt\n"
814                             "       echo \"add|del VNAME lun [READ_ONLY]\" "
815                                         ">mgmt\n";
816
817         return sprintf(buf, help);
818 }
819
820 static ssize_t scst_luns_mgmt_store(struct kobject *kobj,
821                                     struct kobj_attribute *attr,
822                                     const char *buf, size_t count)
823 {
824         int res, virt = 0, read_only = 0, action;
825         char *buffer, *p, *e = NULL;
826         unsigned int host, channel = 0, id = 0, lun = 0, virt_lun;
827         struct scst_acg *acg;
828         struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
829         struct scst_device *d, *dev = NULL;
830         struct scst_tgt *tgt;
831
832 #define SCST_LUN_ACTION_ADD     1
833 #define SCST_LUN_ACTION_DEL     2
834 #define SCST_LUN_ACTION_REPLACE 3
835
836         TRACE_ENTRY();
837
838         tgt = container_of(kobj->parent, struct scst_tgt, tgt_kobj);
839         acg = tgt->default_acg;
840
841         buffer = kzalloc(count+1, GFP_KERNEL);
842         if (buffer == NULL) {
843                 res = -ENOMEM;
844                 goto out;
845         }
846
847         memcpy(buffer, buf, count);
848         buffer[count] = '\0';
849         p = buffer;
850
851         p = buffer;
852         if (p[strlen(p) - 1] == '\n')
853                 p[strlen(p) - 1] = '\0';
854         if (strncasecmp("add", p, 3) == 0) {
855                 p += 3;
856                 action = SCST_LUN_ACTION_ADD;
857         } else if (strncasecmp("del", p, 3) == 0) {
858                 p += 3;
859                 action = SCST_LUN_ACTION_DEL;
860         } else if (!strncasecmp("replace", p, 7)) {
861                 p += 7;
862                 action = SCST_LUN_ACTION_REPLACE;
863         } else {
864                 PRINT_ERROR("Unknown action \"%s\"", p);
865                 res = -EINVAL;
866                 goto out_free;
867         }
868
869         if (!isspace(*p)) {
870                 PRINT_ERROR("%s", "Syntax error");
871                 res = -EINVAL;
872                 goto out_free;
873         }
874
875         res = scst_suspend_activity(true);
876         if (res != 0)
877                 goto out_free;
878
879         if (mutex_lock_interruptible(&scst_mutex) != 0) {
880                 res = -EINTR;
881                 goto out_free_resume;
882         }
883
884         while (isspace(*p) && *p != '\0')
885                 p++;
886         e = p; /* save p */
887         host = simple_strtoul(p, &p, 0);
888         if (*p == ':') {
889                 channel = simple_strtoul(p + 1, &p, 0);
890                 id = simple_strtoul(p + 1, &p, 0);
891                 lun = simple_strtoul(p + 1, &p, 0);
892                 e = p;
893         } else {
894                 virt++;
895                 p = e; /* restore p */
896                 while (!isspace(*e) && *e != '\0')
897                         e++;
898                 *e = '\0';
899         }
900
901         list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
902                 if (virt) {
903                         if (d->virt_id && !strcmp(d->virt_name, p)) {
904                                 dev = d;
905                                 TRACE_DBG("Virt device %p (%s) found",
906                                           dev, p);
907                                 break;
908                         }
909                 } else {
910                         if (d->scsi_dev &&
911                             d->scsi_dev->host->host_no == host &&
912                             d->scsi_dev->channel == channel &&
913                             d->scsi_dev->id == id &&
914                             d->scsi_dev->lun == lun) {
915                                 dev = d;
916                                 TRACE_DBG("Dev %p (%d:%d:%d:%d) found",
917                                           dev, host, channel, id, lun);
918                                 break;
919                         }
920                 }
921         }
922         if (dev == NULL) {
923                 if (virt) {
924                         PRINT_ERROR("Virt device %s not found", p);
925                 } else {
926                         PRINT_ERROR("Device %d:%d:%d:%d not found",
927                                     host, channel, id, lun);
928                 }
929                 res = -EINVAL;
930                 goto out_free_up;
931         }
932
933         switch (action) {
934         case SCST_LUN_ACTION_ADD:
935         case SCST_LUN_ACTION_REPLACE:
936         {
937                 bool dev_replaced = false;
938
939                 e++;
940                 while (isspace(*e) && *e != '\0')
941                         e++;
942                 virt_lun = simple_strtoul(e, &e, 0);
943
944                 while (isspace(*e) && *e != '\0')
945                         e++;
946
947                 if (*e != '\0') {
948                         if ((strncasecmp("READ_ONLY", e, 9) == 0) &&
949                             (isspace(e[9]) || (e[9] == '\0')))
950                                 read_only = 1;
951                         else {
952                                 PRINT_ERROR("Unknown option \"%s\"", e);
953                                 res = -EINVAL;
954                                 goto out_free_up;
955                         }
956                 }
957
958                 acg_dev = NULL;
959                 list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list,
960                                     acg_dev_list_entry) {
961                         if (acg_dev_tmp->lun == virt_lun) {
962                                 acg_dev = acg_dev_tmp;
963                                 break;
964                         }
965                 }
966
967                 if (acg_dev != NULL) {
968                         if (action == SCST_LUN_ACTION_ADD) {
969                                 PRINT_ERROR("virt lun %d already exists in "
970                                         "group %s", virt_lun, acg->acg_name);
971                                 res = -EINVAL;
972                                 goto out_free_up;
973                         } else {
974                                 /* Replace */
975                                 res = scst_acg_remove_dev(acg, acg_dev->dev,
976                                                 false);
977                                 if (res != 0)
978                                         goto out_free_up;
979
980                                 dev_replaced = true;
981                         }
982                 }
983
984                 res = scst_acg_add_dev(acg, dev, virt_lun, read_only,
985                                         !dev_replaced);
986                 if (res != 0)
987                         goto out_free_up;
988
989                 res = scst_create_acg_dev_sysfs(acg, virt_lun, kobj);
990                 if (res != 0) {
991                         PRINT_ERROR("%s", "Creation of acg_dev kobject failed");
992                         goto out_remove_acg_dev;
993                 }
994
995                 if (dev_replaced) {
996                         struct scst_tgt_dev *tgt_dev;
997
998                         list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
999                                         dev_tgt_dev_list_entry) {
1000                                 if ((tgt_dev->acg_dev->acg == acg) &&
1001                                     (tgt_dev->lun == virt_lun)) {
1002                                         TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED"
1003                                                 " on tgt_dev %p", tgt_dev);
1004                                         scst_gen_aen_or_ua(tgt_dev,
1005                                                 SCST_LOAD_SENSE(scst_sense_inquery_data_changed));
1006                                 }
1007                         }
1008                 }
1009
1010                 break;
1011         }
1012         case SCST_LUN_ACTION_DEL:
1013                 res = scst_acg_remove_dev(acg, dev, true);
1014                 if (res != 0)
1015                         goto out_free_up;
1016                 break;
1017         }
1018
1019         res = count;
1020
1021 out_free_up:
1022         mutex_unlock(&scst_mutex);
1023
1024 out_free_resume:
1025         scst_resume_activity();
1026
1027 out_free:
1028         kfree(buffer);
1029
1030 out:
1031         TRACE_EXIT_RES(res);
1032         return res;
1033
1034 out_remove_acg_dev:
1035         scst_acg_remove_dev(acg, dev, true);
1036         goto out_free_up;
1037
1038 #undef SCST_LUN_ACTION_ADD
1039 #undef SCST_LUN_ACTION_DEL
1040 #undef SCST_LUN_ACTION_REPLACE
1041 }
1042
1043 /*
1044  * SGV directory implementation
1045  */
1046
1047 static struct kobj_attribute sgv_stat_attr =
1048         __ATTR(stats, S_IRUGO, sgv_sysfs_stat_show, NULL);
1049
1050 static struct attribute *sgv_attrs[] = {
1051         &sgv_stat_attr.attr,
1052         NULL,
1053 };
1054
1055 static void sgv_kobj_release(struct kobject *kobj)
1056 {
1057         struct sgv_pool *pool;
1058
1059         TRACE_ENTRY();
1060
1061         pool = container_of(kobj, struct sgv_pool, sgv_kobj);
1062
1063         sgv_pool_destroy(pool);
1064
1065         TRACE_EXIT();
1066         return;
1067 }
1068
1069 static struct kobj_type sgv_pool_ktype = {
1070         .sysfs_ops = &scst_sysfs_ops,
1071         .release = sgv_kobj_release,
1072         .default_attrs = sgv_attrs,
1073 };
1074
1075 int scst_create_sgv_sysfs(struct sgv_pool *pool)
1076 {
1077         int retval;
1078
1079         TRACE_ENTRY();
1080
1081         pool->sgv_kobj_initialized = 1;
1082
1083         retval = kobject_init_and_add(&pool->sgv_kobj, &sgv_pool_ktype,
1084                         scst_sgv_kobj, pool->name);
1085         if (retval != 0) {
1086                 PRINT_ERROR("Can't add sgv pool %s to sysfs", pool->name);
1087                 goto out;
1088         }
1089
1090 out:
1091         TRACE_EXIT_RES(retval);
1092         return retval;
1093 }
1094
1095 /* pool can be dead upon exit from this function! */
1096 void scst_sgv_sysfs_put(struct sgv_pool *pool)
1097 {
1098         if (pool->sgv_kobj_initialized) {
1099                 kobject_del(&pool->sgv_kobj);
1100                 kobject_put(&pool->sgv_kobj);
1101         } else
1102                 sgv_pool_destroy(pool);
1103         return;
1104 }
1105
1106 static struct kobj_attribute sgv_global_stat_attr =
1107         __ATTR(global_stats, S_IRUGO, sgv_sysfs_global_stat_show, NULL);
1108
1109 static struct attribute *sgv_default_attrs[] = {
1110         &sgv_global_stat_attr.attr,
1111         NULL,
1112 };
1113
1114 static struct kobj_type sgv_ktype = {
1115         .sysfs_ops = &scst_sysfs_ops,
1116         .release = scst_sysfs_release,
1117         .default_attrs = sgv_default_attrs,
1118 };
1119
1120 /*
1121  * SCST sysfs root directory implementation
1122  */
1123
1124 static ssize_t scst_threads_show(struct kobject *kobj,
1125         struct kobj_attribute *attr, char *buf)
1126 {
1127         int count;
1128
1129         TRACE_ENTRY();
1130
1131         count = sprintf(buf, "%d\n", scst_global_threads_count());
1132
1133         TRACE_EXIT();
1134         return count;
1135 }
1136
1137 static ssize_t scst_threads_store(struct kobject *kobj,
1138         struct kobj_attribute *attr, const char *buf, size_t count)
1139 {
1140         int res = count;
1141         int oldtn, newtn, delta;
1142
1143         TRACE_ENTRY();
1144
1145         if (mutex_lock_interruptible(&scst_sysfs_mutex) != 0) {
1146                 res = -EINTR;
1147                 goto out;
1148         }
1149
1150         mutex_lock(&scst_global_threads_mutex);
1151
1152         oldtn = scst_nr_global_threads;
1153         sscanf(buf, "%du", &newtn);
1154
1155         if (newtn <= 0) {
1156                 PRINT_ERROR("Illegal threads num value %d", newtn);
1157                 res = -EINVAL;
1158                 goto out_up_thr_free;
1159         }
1160         delta = newtn - oldtn;
1161         if (delta < 0)
1162                 __scst_del_global_threads(-delta);
1163         else
1164                 __scst_add_global_threads(delta);
1165
1166         PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
1167
1168 out_up_thr_free:
1169         mutex_unlock(&scst_global_threads_mutex);
1170
1171         mutex_unlock(&scst_sysfs_mutex);
1172
1173 out:
1174         TRACE_EXIT_RES(res);
1175         return res;
1176 }
1177
1178 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
1179
1180 static void scst_read_trace_tlb(const struct scst_trace_log *tbl, char *buf,
1181         unsigned long log_level, int *pos)
1182 {
1183         const struct scst_trace_log *t = tbl;
1184
1185         if (t == NULL)
1186                 goto out;
1187
1188         while (t->token) {
1189                 if (log_level & t->val) {
1190                         *pos += sprintf(&buf[*pos], "%s%s",
1191                                         (*pos == 0) ? "" : " | ",
1192                                         t->token);
1193                 }
1194                 t++;
1195         }
1196 out:
1197         return;
1198 }
1199
1200 static ssize_t scst_trace_level_show(const struct scst_trace_log *local_tbl,
1201         unsigned long log_level, char *buf, const char *help)
1202 {
1203         int pos = 0;
1204
1205         scst_read_trace_tlb(scst_trace_tbl, buf, log_level, &pos);
1206         scst_read_trace_tlb(local_tbl, buf, log_level, &pos);
1207
1208         pos += sprintf(&buf[pos], "\n\n\nUsage:\n"
1209                 "       echo \"all|none|default\" >trace_level\n"
1210                 "       echo \"value DEC|0xHEX|0OCT\" >trace_level\n"
1211                 "       echo \"add|del TOKEN\" >trace_level\n"
1212                 "\nwhere TOKEN is one of [debug, function, line, pid,\n"
1213                 "                      entryexit, buff, mem, sg, out_of_mem,\n"
1214                 "                      special, scsi, mgmt, minor,\n"
1215                 "                      mgmt_minor, mgmt_dbg, scsi_serializing,\n"
1216                 "                      retry, recv_bot, send_bot, recv_top,\n"
1217                 "                      send_top%s]", help != NULL ? help : "");
1218
1219         return pos;
1220 }
1221
1222 static ssize_t scst_main_trace_level_show(struct kobject *kobj,
1223         struct kobj_attribute *attr, char *buf)
1224 {
1225         return scst_trace_level_show(scst_local_trace_tbl, trace_flag,
1226                         buf, NULL);
1227 }
1228
1229 static int scst_write_trace(const char *buf, size_t length,
1230         unsigned long *log_level, unsigned long default_level,
1231         const char *name, const struct scst_trace_log *tbl)
1232 {
1233         int res = length;
1234         int action;
1235         unsigned long level = 0, oldlevel;
1236         char *buffer, *p, *e;
1237         const struct scst_trace_log *t;
1238
1239 #define SCST_TRACE_ACTION_ALL           1
1240 #define SCST_TRACE_ACTION_NONE          2
1241 #define SCST_TRACE_ACTION_DEFAULT       3
1242 #define SCST_TRACE_ACTION_ADD           4
1243 #define SCST_TRACE_ACTION_DEL           5
1244 #define SCST_TRACE_ACTION_VALUE         6
1245
1246         TRACE_ENTRY();
1247
1248         if ((buf == NULL) || (length == 0)) {
1249                 res = -EINVAL;
1250                 goto out;
1251         }
1252
1253         buffer = kmalloc(length+1, GFP_KERNEL);
1254         if (buffer == NULL) {
1255                 PRINT_ERROR("Unable to alloc intermediate buffer (size %d)",
1256                         length+1);
1257                 res = -ENOMEM;
1258                 goto out;
1259         }
1260         memcpy(buffer, buf, length);
1261         buffer[length] = '\0';
1262
1263         p = buffer;
1264         if (!strncasecmp("all", p, 3)) {
1265                 action = SCST_TRACE_ACTION_ALL;
1266         } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) {
1267                 action = SCST_TRACE_ACTION_NONE;
1268         } else if (!strncasecmp("default", p, 7)) {
1269                 action = SCST_TRACE_ACTION_DEFAULT;
1270         } else if (!strncasecmp("add", p, 3)) {
1271                 p += 3;
1272                 action = SCST_TRACE_ACTION_ADD;
1273         } else if (!strncasecmp("del", p, 3)) {
1274                 p += 3;
1275                 action = SCST_TRACE_ACTION_DEL;
1276         } else if (!strncasecmp("value", p, 5)) {
1277                 p += 5;
1278                 action = SCST_TRACE_ACTION_VALUE;
1279         } else {
1280                 if (p[strlen(p) - 1] == '\n')
1281                         p[strlen(p) - 1] = '\0';
1282                 PRINT_ERROR("Unknown action \"%s\"", p);
1283                 res = -EINVAL;
1284                 goto out_free;
1285         }
1286
1287         switch (action) {
1288         case SCST_TRACE_ACTION_ADD:
1289         case SCST_TRACE_ACTION_DEL:
1290         case SCST_TRACE_ACTION_VALUE:
1291                 if (!isspace(*p)) {
1292                         PRINT_ERROR("%s", "Syntax error");
1293                         res = -EINVAL;
1294                         goto out_free;
1295                 }
1296         }
1297
1298         switch (action) {
1299         case SCST_TRACE_ACTION_ALL:
1300                 level = TRACE_ALL;
1301                 break;
1302         case SCST_TRACE_ACTION_DEFAULT:
1303                 level = default_level;
1304                 break;
1305         case SCST_TRACE_ACTION_NONE:
1306                 level = TRACE_NULL;
1307                 break;
1308         case SCST_TRACE_ACTION_ADD:
1309         case SCST_TRACE_ACTION_DEL:
1310                 while (isspace(*p) && *p != '\0')
1311                         p++;
1312                 e = p;
1313                 while (!isspace(*e) && *e != '\0')
1314                         e++;
1315                 *e = 0;
1316                 if (tbl) {
1317                         t = tbl;
1318                         while (t->token) {
1319                                 if (!strcasecmp(p, t->token)) {
1320                                         level = t->val;
1321                                         break;
1322                                 }
1323                                 t++;
1324                         }
1325                 }
1326                 if (level == 0) {
1327                         t = scst_trace_tbl;
1328                         while (t->token) {
1329                                 if (!strcasecmp(p, t->token)) {
1330                                         level = t->val;
1331                                         break;
1332                                 }
1333                                 t++;
1334                         }
1335                 }
1336                 if (level == 0) {
1337                         PRINT_ERROR("Unknown token \"%s\"", p);
1338                         res = -EINVAL;
1339                         goto out_free;
1340                 }
1341                 break;
1342         case SCST_TRACE_ACTION_VALUE:
1343                 while (isspace(*p) && *p != '\0')
1344                         p++;
1345                 res = strict_strtoul(p, 0, &level);
1346                 if (res != 0) {
1347                         PRINT_ERROR("Invalud trace value \"%s\"", p);
1348                         res = -EINVAL;
1349                         goto out_free;
1350                 }
1351                 break;
1352         }
1353
1354         oldlevel = *log_level;
1355
1356         switch (action) {
1357         case SCST_TRACE_ACTION_ADD:
1358                 *log_level |= level;
1359                 break;
1360         case SCST_TRACE_ACTION_DEL:
1361                 *log_level &= ~level;
1362                 break;
1363         default:
1364                 *log_level = level;
1365                 break;
1366         }
1367
1368         PRINT_INFO("Changed trace level for \"%s\": old 0x%08lx, new 0x%08lx",
1369                 name, oldlevel, *log_level);
1370
1371 out_free:
1372         kfree(buffer);
1373 out:
1374         TRACE_EXIT_RES(res);
1375         return res;
1376
1377 #undef SCST_TRACE_ACTION_ALL
1378 #undef SCST_TRACE_ACTION_NONE
1379 #undef SCST_TRACE_ACTION_DEFAULT
1380 #undef SCST_TRACE_ACTION_ADD
1381 #undef SCST_TRACE_ACTION_DEL
1382 #undef SCST_TRACE_ACTION_VALUE
1383 }
1384
1385 static ssize_t scst_main_trace_level_store(struct kobject *kobj,
1386         struct kobj_attribute *attr, const char *buf, size_t count)
1387 {
1388         int res;
1389
1390         TRACE_ENTRY();
1391
1392         if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
1393                 res = -EINTR;
1394                 goto out;
1395         }
1396
1397         res = scst_write_trace(buf, count, &trace_flag,
1398                 SCST_DEFAULT_LOG_FLAGS, "scst", scst_local_trace_tbl);
1399
1400         mutex_unlock(&scst_log_mutex);
1401
1402 out:
1403         TRACE_EXIT_RES(res);
1404         return res;
1405 }
1406
1407 #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
1408
1409 static ssize_t scst_version_show(struct kobject *kobj,
1410                                  struct kobj_attribute *attr,
1411                                  char *buf)
1412 {
1413         TRACE_ENTRY();
1414
1415         sprintf(buf, "%s\n", SCST_VERSION_STRING);
1416
1417 #ifdef CONFIG_SCST_STRICT_SERIALIZING
1418         strcat(buf, "Strict serializing enabled\n");
1419 #endif
1420
1421 #ifdef CONFIG_SCST_EXTRACHECKS
1422         strcat(buf, "EXTRACHECKS\n");
1423 #endif
1424
1425 #ifdef CONFIG_SCST_TRACING
1426         strcat(buf, "TRACING\n");
1427 #endif
1428
1429 #ifdef CONFIG_SCST_DEBUG
1430         strcat(buf, "DEBUG\n");
1431 #endif
1432
1433 #ifdef CONFIG_SCST_DEBUG_TM
1434         strcat(buf, "DEBUG_TM\n");
1435 #endif
1436
1437 #ifdef CONFIG_SCST_DEBUG_RETRY
1438         strcat(buf, "DEBUG_RETRY\n");
1439 #endif
1440
1441 #ifdef CONFIG_SCST_DEBUG_OOM
1442         strcat(buf, "DEBUG_OOM\n");
1443 #endif
1444
1445 #ifdef CONFIG_SCST_DEBUG_SN
1446         strcat(buf, "DEBUG_SN\n");
1447 #endif
1448
1449 #ifdef CONFIG_SCST_USE_EXPECTED_VALUES
1450         strcat(buf, "USE_EXPECTED_VALUES\n");
1451 #endif
1452
1453 #ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
1454         strcat(buf, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
1455 #endif
1456
1457 #ifdef CONFIG_SCST_STRICT_SECURITY
1458         strcat(buf, "SCST_STRICT_SECURITY\n");
1459 #endif
1460
1461         TRACE_EXIT();
1462         return strlen(buf);
1463 }
1464
1465 static struct kobj_attribute scst_threads_attr =
1466         __ATTR(threads, S_IRUGO | S_IWUSR, scst_threads_show,
1467                scst_threads_store);
1468
1469 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
1470 static struct kobj_attribute scst_trace_level_attr =
1471         __ATTR(trace_level, S_IRUGO | S_IWUSR, scst_main_trace_level_show,
1472                scst_main_trace_level_store);
1473 #endif
1474
1475 static struct kobj_attribute scst_version_attr =
1476         __ATTR(version, S_IRUGO, scst_version_show, NULL);
1477
1478 static struct attribute *scst_sysfs_root_default_attrs[] = {
1479         &scst_threads_attr.attr,
1480 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
1481         &scst_trace_level_attr.attr,
1482 #endif
1483         &scst_version_attr.attr,
1484         NULL,
1485 };
1486
1487 static void scst_sysfs_root_release(struct kobject *kobj)
1488 {
1489         complete_all(&scst_sysfs_root_release_completion);
1490 }
1491
1492 static ssize_t scst_show(struct kobject *kobj, struct attribute *attr,
1493                          char *buf)
1494 {
1495         struct kobj_attribute *kobj_attr;
1496         kobj_attr = container_of(attr, struct kobj_attribute, attr);
1497
1498         return kobj_attr->show(kobj, kobj_attr, buf);
1499 }
1500
1501 static ssize_t scst_store(struct kobject *kobj, struct attribute *attr,
1502                           const char *buf, size_t count)
1503 {
1504         struct kobj_attribute *kobj_attr;
1505         kobj_attr = container_of(attr, struct kobj_attribute, attr);
1506
1507         return kobj_attr->store(kobj, kobj_attr, buf, count);
1508 }
1509
1510 static struct sysfs_ops scst_sysfs_ops = {
1511         .show = scst_show,
1512         .store = scst_store,
1513 };
1514
1515 static struct kobj_type scst_sysfs_root_ktype = {
1516         .sysfs_ops = &scst_sysfs_ops,
1517         .release = scst_sysfs_root_release,
1518         .default_attrs = scst_sysfs_root_default_attrs,
1519 };
1520
1521 static void scst_devt_free(struct kobject *kobj)
1522 {
1523         struct scst_dev_type *devt;
1524
1525         TRACE_ENTRY();
1526
1527         devt = container_of(kobj, struct scst_dev_type, devt_kobj);
1528
1529         complete_all(&devt->devt_kobj_release_compl);
1530
1531         scst_devt_cleanup(devt);
1532
1533         TRACE_EXIT();
1534         return;
1535 }
1536
1537 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
1538
1539 static ssize_t scst_devt_trace_level_show(struct kobject *kobj,
1540         struct kobj_attribute *attr, char *buf)
1541 {
1542         struct scst_dev_type *devt;
1543
1544         devt = container_of(kobj, struct scst_dev_type, devt_kobj);
1545
1546         return scst_trace_level_show(devt->trace_tbl,
1547                 devt->trace_flags ? *devt->trace_flags : 0, buf,
1548                 devt->trace_tbl_help);
1549 }
1550
1551 static ssize_t scst_devt_trace_level_store(struct kobject *kobj,
1552         struct kobj_attribute *attr, const char *buf, size_t count)
1553 {
1554         int res;
1555         struct scst_dev_type *devt;
1556
1557         TRACE_ENTRY();
1558
1559         devt = container_of(kobj, struct scst_dev_type, devt_kobj);
1560
1561         if (mutex_lock_interruptible(&scst_log_mutex) != 0) {
1562                 res = -EINTR;
1563                 goto out;
1564         }
1565
1566         res = scst_write_trace(buf, count, devt->trace_flags,
1567                 devt->default_trace_flags, devt->name, devt->trace_tbl);
1568
1569         mutex_unlock(&scst_log_mutex);
1570
1571 out:
1572         TRACE_EXIT_RES(res);
1573         return res;
1574 }
1575
1576 static struct kobj_attribute devt_trace_attr =
1577         __ATTR(trace_level, S_IRUGO | S_IWUSR,
1578                scst_devt_trace_level_show, scst_devt_trace_level_store);
1579
1580 #endif /* #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
1581
1582 static ssize_t scst_devt_type_show(struct kobject *kobj,
1583         struct kobj_attribute *attr, char *buf)
1584 {
1585         int pos;
1586         struct scst_dev_type *devt;
1587
1588         devt = container_of(kobj, struct scst_dev_type, devt_kobj);
1589
1590         pos = sprintf(buf, "%d - %s\n", devt->type,
1591                 (unsigned)devt->type > ARRAY_SIZE(scst_dev_handler_types) ?
1592                         "unknown" : scst_dev_handler_types[devt->type]);
1593
1594         return pos;
1595 }
1596
1597 static struct kobj_attribute scst_devt_type_attr =
1598         __ATTR(type, S_IRUGO, scst_devt_type_show, NULL);
1599
1600 static struct attribute *scst_devt_default_attrs[] = {
1601         &scst_devt_type_attr.attr,
1602         NULL,
1603 };
1604
1605 static struct kobj_type scst_devt_ktype = {
1606         .sysfs_ops = &scst_sysfs_ops,
1607         .release = scst_devt_free,
1608         .default_attrs = scst_devt_default_attrs,
1609 };
1610
1611 int scst_create_devt_sysfs(struct scst_dev_type *devt)
1612 {
1613         int retval;
1614         struct kobject *parent;
1615         const struct attribute **pattr;
1616
1617         TRACE_ENTRY();
1618
1619         init_completion(&devt->devt_kobj_release_compl);
1620
1621         if (devt->parent != NULL)
1622                 parent = &devt->parent->devt_kobj;
1623         else
1624                 parent = scst_handlers_kobj;
1625
1626         devt->devt_kobj_initialized = 1;
1627
1628         retval = kobject_init_and_add(&devt->devt_kobj, &scst_devt_ktype,
1629                         parent, devt->name);
1630         if (retval != 0) {
1631                 PRINT_ERROR("Can't add devt %s to sysfs", devt->name);
1632                 goto out;
1633         }
1634
1635         /*
1636          * In case of errors there's no need for additional cleanup, because
1637          * it will be done by the _put function() called by the caller.
1638          */
1639
1640         pattr = devt->devt_attrs;
1641         if (pattr != NULL) {
1642                 while (*pattr != NULL) {
1643                         retval = sysfs_create_file(&devt->devt_kobj, *pattr);
1644                         if (retval != 0) {
1645                                 PRINT_ERROR("Can't add devt attr %s for dev "
1646                                         "handler %s", (*pattr)->name,
1647                                         devt->name);
1648                                 goto out;
1649                         }
1650                         pattr++;
1651                 }
1652         }
1653
1654 #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
1655         if (devt->trace_flags != NULL) {
1656                 retval = sysfs_create_file(&devt->devt_kobj,
1657                                 &devt_trace_attr.attr);
1658                 if (retval != 0) {
1659                         PRINT_ERROR("Can't add devt trace_flag for dev "
1660                                 "handler %s", devt->name);
1661                         goto out;
1662                 }
1663         }
1664 #endif
1665
1666 out:
1667         TRACE_EXIT_RES(retval);
1668         return retval;
1669 }
1670
1671 void scst_devt_sysfs_put(struct scst_dev_type *devt)
1672 {
1673         TRACE_ENTRY();
1674
1675         if (devt->devt_kobj_initialized) {
1676                 int rc;
1677
1678                 kobject_del(&devt->devt_kobj);
1679                 kobject_put(&devt->devt_kobj);
1680
1681                 rc = wait_for_completion_timeout(&devt->devt_kobj_release_compl, HZ);
1682                 if (rc == 0) {
1683                         PRINT_INFO("Waiting for releasing sysfs entry "
1684                                 "for dev handler template %s...", devt->name);
1685                         wait_for_completion(&devt->devt_kobj_release_compl);
1686                         PRINT_INFO("Done waiting for releasing sysfs entry "
1687                                 "for dev handler template %s", devt->name);
1688                 }
1689         } else
1690                 scst_devt_cleanup(devt);
1691
1692         TRACE_EXIT();
1693         return;
1694 }
1695
1696 int __init scst_sysfs_init(void)
1697 {
1698         int retval = 0;
1699
1700         TRACE_ENTRY();
1701
1702         retval = kobject_init_and_add(&scst_sysfs_root_kobj,
1703                         &scst_sysfs_root_ktype, kernel_kobj, "%s", "scst_tgt");
1704         if (retval != 0)
1705                 goto sysfs_root_add_error;
1706
1707         scst_targets_kobj = kobject_create_and_add("targets",
1708                                 &scst_sysfs_root_kobj);
1709         if (scst_targets_kobj == NULL)
1710                 goto targets_kobj_error;
1711
1712         scst_devices_kobj = kobject_create_and_add("devices",
1713                                 &scst_sysfs_root_kobj);
1714         if (scst_devices_kobj == NULL)
1715                 goto devices_kobj_error;
1716
1717         scst_sgv_kobj = kzalloc(sizeof(*scst_sgv_kobj), GFP_KERNEL);
1718         if (scst_sgv_kobj == NULL)
1719                 goto sgv_kobj_error;
1720
1721         retval = kobject_init_and_add(scst_sgv_kobj, &sgv_ktype,
1722                         &scst_sysfs_root_kobj, "%s", "sgv");
1723         if (retval != 0)
1724                 goto sgv_kobj_add_error;
1725
1726         scst_handlers_kobj = kobject_create_and_add("handlers",
1727                                         &scst_sysfs_root_kobj);
1728         if (scst_handlers_kobj == NULL)
1729                 goto handlers_kobj_error;
1730
1731
1732 out:
1733         TRACE_EXIT_RES(retval);
1734         return retval;
1735
1736 handlers_kobj_error:
1737         kobject_del(scst_sgv_kobj);
1738
1739 sgv_kobj_add_error:
1740         kobject_put(scst_sgv_kobj);
1741
1742 sgv_kobj_error:
1743         kobject_del(scst_devices_kobj);
1744         kobject_put(scst_devices_kobj);
1745
1746 devices_kobj_error:
1747         kobject_del(scst_targets_kobj);
1748         kobject_put(scst_targets_kobj);
1749
1750 targets_kobj_error:
1751         kobject_del(&scst_sysfs_root_kobj);
1752
1753 sysfs_root_add_error:
1754         kobject_put(&scst_sysfs_root_kobj);
1755
1756         if (retval == 0)
1757                 retval = -EINVAL;
1758         goto out;
1759 }
1760
1761 void __exit scst_sysfs_cleanup(void)
1762 {
1763         TRACE_ENTRY();
1764
1765         PRINT_INFO("%s", "Exiting SCST sysfs hierarchy...");
1766
1767         kobject_del(scst_sgv_kobj);
1768         kobject_put(scst_sgv_kobj);
1769
1770         kobject_del(scst_devices_kobj);
1771         kobject_put(scst_devices_kobj);
1772
1773         kobject_del(scst_targets_kobj);
1774         kobject_put(scst_targets_kobj);
1775
1776         kobject_del(scst_handlers_kobj);
1777         kobject_put(scst_handlers_kobj);
1778
1779         kobject_del(&scst_sysfs_root_kobj);
1780         kobject_put(&scst_sysfs_root_kobj);
1781
1782         wait_for_completion(&scst_sysfs_root_release_completion);
1783
1784         PRINT_INFO("%s", "Exiting SCST sysfs hierarchy done");
1785
1786         TRACE_EXIT();
1787         return;
1788 }