1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * tape device driver for S/390 and zSeries tapes. |
4 | * |
5 | * S390 and zSeries version |
6 | * Copyright IBM Corp. 2001 |
7 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
8 | * Michael Holzheu <holzheu@de.ibm.com> |
9 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> |
10 | * |
11 | * PROCFS Functions |
12 | */ |
13 | |
14 | #define KMSG_COMPONENT "tape" |
15 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
16 | |
17 | #include <linux/module.h> |
18 | #include <linux/vmalloc.h> |
19 | #include <linux/seq_file.h> |
20 | #include <linux/proc_fs.h> |
21 | |
22 | #define TAPE_DBF_AREA tape_core_dbf |
23 | |
24 | #include "tape.h" |
25 | |
26 | static const char *tape_med_st_verbose[MS_SIZE] = |
27 | { |
28 | [MS_UNKNOWN] = "UNKNOWN " , |
29 | [MS_LOADED] = "LOADED " , |
30 | [MS_UNLOADED] = "UNLOADED" |
31 | }; |
32 | |
33 | /* our proc tapedevices entry */ |
34 | static struct proc_dir_entry *tape_proc_devices; |
35 | |
36 | /* |
37 | * Show function for /proc/tapedevices |
38 | */ |
39 | static int tape_proc_show(struct seq_file *m, void *v) |
40 | { |
41 | struct tape_device *device; |
42 | struct tape_request *request; |
43 | const char *str; |
44 | unsigned long n; |
45 | |
46 | n = (unsigned long) v - 1; |
47 | if (!n) { |
48 | seq_printf(m, fmt: "TapeNo\tBusID CuType/Model\t" |
49 | "DevType/Model\tBlkSize\tState\tOp\tMedState\n" ); |
50 | } |
51 | device = tape_find_device(devindex: n); |
52 | if (IS_ERR(ptr: device)) |
53 | return 0; |
54 | spin_lock_irq(lock: get_ccwdev_lock(device->cdev)); |
55 | seq_printf(m, fmt: "%d\t" , (int) n); |
56 | seq_printf(m, fmt: "%-10.10s " , dev_name(&device->cdev->dev)); |
57 | seq_printf(m, fmt: "%04X/" , device->cdev->id.cu_type); |
58 | seq_printf(m, fmt: "%02X\t" , device->cdev->id.cu_model); |
59 | seq_printf(m, fmt: "%04X/" , device->cdev->id.dev_type); |
60 | seq_printf(m, fmt: "%02X\t\t" , device->cdev->id.dev_model); |
61 | if (device->char_data.block_size == 0) |
62 | seq_printf(m, fmt: "auto\t" ); |
63 | else |
64 | seq_printf(m, fmt: "%i\t" , device->char_data.block_size); |
65 | if (device->tape_state >= 0 && |
66 | device->tape_state < TS_SIZE) |
67 | str = tape_state_verbose[device->tape_state]; |
68 | else |
69 | str = "UNKNOWN" ; |
70 | seq_printf(m, fmt: "%s\t" , str); |
71 | if (!list_empty(head: &device->req_queue)) { |
72 | request = list_entry(device->req_queue.next, |
73 | struct tape_request, list); |
74 | str = tape_op_verbose[request->op]; |
75 | } else |
76 | str = "---" ; |
77 | seq_printf(m, fmt: "%s\t" , str); |
78 | seq_printf(m, fmt: "%s\n" , tape_med_st_verbose[device->medium_state]); |
79 | spin_unlock_irq(lock: get_ccwdev_lock(device->cdev)); |
80 | tape_put_device(device); |
81 | return 0; |
82 | } |
83 | |
84 | static void *tape_proc_start(struct seq_file *m, loff_t *pos) |
85 | { |
86 | if (*pos >= 256 / TAPE_MINORS_PER_DEV) |
87 | return NULL; |
88 | return (void *)((unsigned long) *pos + 1); |
89 | } |
90 | |
91 | static void *tape_proc_next(struct seq_file *m, void *v, loff_t *pos) |
92 | { |
93 | ++*pos; |
94 | return tape_proc_start(m, pos); |
95 | } |
96 | |
97 | static void tape_proc_stop(struct seq_file *m, void *v) |
98 | { |
99 | } |
100 | |
101 | static const struct seq_operations tape_proc_seq = { |
102 | .start = tape_proc_start, |
103 | .next = tape_proc_next, |
104 | .stop = tape_proc_stop, |
105 | .show = tape_proc_show, |
106 | }; |
107 | |
108 | /* |
109 | * Initialize procfs stuff on startup |
110 | */ |
111 | void |
112 | tape_proc_init(void) |
113 | { |
114 | tape_proc_devices = proc_create_seq("tapedevices" , 0444, NULL, |
115 | &tape_proc_seq); |
116 | } |
117 | |
118 | /* |
119 | * Cleanup all stuff registered to the procfs |
120 | */ |
121 | void |
122 | tape_proc_cleanup(void) |
123 | { |
124 | if (tape_proc_devices != NULL) |
125 | remove_proc_entry ("tapedevices" , NULL); |
126 | } |
127 | |