Commit | Line | Data |
---|---|---|
293d984f PT |
1 | /* |
2 | * drivers/s390/net/ctcm_sysfs.c | |
3 | * | |
4 | * Copyright IBM Corp. 2007, 2007 | |
5 | * Authors: Peter Tiedemann (ptiedem@de.ibm.com) | |
6 | * | |
7 | */ | |
8 | ||
9 | #undef DEBUG | |
10 | #undef DEBUGDATA | |
11 | #undef DEBUGCCW | |
12 | ||
2a7c6f2c PT |
13 | #define KMSG_COMPONENT "ctcm" |
14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
15 | ||
293d984f | 16 | #include <linux/sysfs.h> |
5a0e3ad6 | 17 | #include <linux/slab.h> |
293d984f PT |
18 | #include "ctcm_main.h" |
19 | ||
20 | /* | |
21 | * sysfs attributes | |
22 | */ | |
23 | ||
24 | static ssize_t ctcm_buffer_show(struct device *dev, | |
25 | struct device_attribute *attr, char *buf) | |
26 | { | |
27 | struct ctcm_priv *priv = dev_get_drvdata(dev); | |
28 | ||
29 | if (!priv) | |
30 | return -ENODEV; | |
31 | return sprintf(buf, "%d\n", priv->buffer_size); | |
32 | } | |
33 | ||
34 | static ssize_t ctcm_buffer_write(struct device *dev, | |
35 | struct device_attribute *attr, const char *buf, size_t count) | |
36 | { | |
37 | struct net_device *ndev; | |
38 | int bs1; | |
39 | struct ctcm_priv *priv = dev_get_drvdata(dev); | |
40 | ||
41 | if (!(priv && priv->channel[READ] && | |
42 | (ndev = priv->channel[READ]->netdev))) { | |
43 | CTCM_DBF_TEXT(SETUP, CTC_DBF_ERROR, "bfnondev"); | |
44 | return -ENODEV; | |
45 | } | |
46 | ||
47 | sscanf(buf, "%u", &bs1); | |
48 | if (bs1 > CTCM_BUFSIZE_LIMIT) | |
49 | goto einval; | |
50 | if (bs1 < (576 + LL_HEADER_LENGTH + 2)) | |
51 | goto einval; | |
52 | priv->buffer_size = bs1; /* just to overwrite the default */ | |
53 | ||
54 | if ((ndev->flags & IFF_RUNNING) && | |
55 | (bs1 < (ndev->mtu + LL_HEADER_LENGTH + 2))) | |
56 | goto einval; | |
57 | ||
58 | priv->channel[READ]->max_bufsize = bs1; | |
59 | priv->channel[WRITE]->max_bufsize = bs1; | |
60 | if (!(ndev->flags & IFF_RUNNING)) | |
61 | ndev->mtu = bs1 - LL_HEADER_LENGTH - 2; | |
62 | priv->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED; | |
63 | priv->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED; | |
64 | ||
65 | CTCM_DBF_DEV(SETUP, ndev, buf); | |
66 | return count; | |
67 | ||
68 | einval: | |
69 | CTCM_DBF_DEV(SETUP, ndev, "buff_err"); | |
70 | return -EINVAL; | |
71 | } | |
72 | ||
73 | static void ctcm_print_statistics(struct ctcm_priv *priv) | |
74 | { | |
75 | char *sbuf; | |
76 | char *p; | |
77 | ||
78 | if (!priv) | |
79 | return; | |
80 | sbuf = kmalloc(2048, GFP_KERNEL); | |
81 | if (sbuf == NULL) | |
82 | return; | |
83 | p = sbuf; | |
84 | ||
85 | p += sprintf(p, " Device FSM state: %s\n", | |
86 | fsm_getstate_str(priv->fsm)); | |
87 | p += sprintf(p, " RX channel FSM state: %s\n", | |
88 | fsm_getstate_str(priv->channel[READ]->fsm)); | |
89 | p += sprintf(p, " TX channel FSM state: %s\n", | |
90 | fsm_getstate_str(priv->channel[WRITE]->fsm)); | |
91 | p += sprintf(p, " Max. TX buffer used: %ld\n", | |
92 | priv->channel[WRITE]->prof.maxmulti); | |
93 | p += sprintf(p, " Max. chained SKBs: %ld\n", | |
94 | priv->channel[WRITE]->prof.maxcqueue); | |
95 | p += sprintf(p, " TX single write ops: %ld\n", | |
96 | priv->channel[WRITE]->prof.doios_single); | |
97 | p += sprintf(p, " TX multi write ops: %ld\n", | |
98 | priv->channel[WRITE]->prof.doios_multi); | |
99 | p += sprintf(p, " Netto bytes written: %ld\n", | |
100 | priv->channel[WRITE]->prof.txlen); | |
101 | p += sprintf(p, " Max. TX IO-time: %ld\n", | |
102 | priv->channel[WRITE]->prof.tx_time); | |
103 | ||
104 | printk(KERN_INFO "Statistics for %s:\n%s", | |
105 | priv->channel[WRITE]->netdev->name, sbuf); | |
106 | kfree(sbuf); | |
107 | return; | |
108 | } | |
109 | ||
110 | static ssize_t stats_show(struct device *dev, | |
111 | struct device_attribute *attr, char *buf) | |
112 | { | |
113 | struct ctcm_priv *priv = dev_get_drvdata(dev); | |
114 | if (!priv) | |
115 | return -ENODEV; | |
116 | ctcm_print_statistics(priv); | |
117 | return sprintf(buf, "0\n"); | |
118 | } | |
119 | ||
120 | static ssize_t stats_write(struct device *dev, struct device_attribute *attr, | |
121 | const char *buf, size_t count) | |
122 | { | |
123 | struct ctcm_priv *priv = dev_get_drvdata(dev); | |
124 | if (!priv) | |
125 | return -ENODEV; | |
126 | /* Reset statistics */ | |
127 | memset(&priv->channel[WRITE]->prof, 0, | |
128 | sizeof(priv->channel[WRITE]->prof)); | |
129 | return count; | |
130 | } | |
131 | ||
132 | static ssize_t ctcm_proto_show(struct device *dev, | |
133 | struct device_attribute *attr, char *buf) | |
134 | { | |
135 | struct ctcm_priv *priv = dev_get_drvdata(dev); | |
136 | if (!priv) | |
137 | return -ENODEV; | |
138 | ||
139 | return sprintf(buf, "%d\n", priv->protocol); | |
140 | } | |
141 | ||
142 | static ssize_t ctcm_proto_store(struct device *dev, | |
143 | struct device_attribute *attr, const char *buf, size_t count) | |
144 | { | |
145 | int value; | |
146 | struct ctcm_priv *priv = dev_get_drvdata(dev); | |
147 | ||
148 | if (!priv) | |
149 | return -ENODEV; | |
150 | sscanf(buf, "%u", &value); | |
151 | if (!((value == CTCM_PROTO_S390) || | |
152 | (value == CTCM_PROTO_LINUX) || | |
153 | (value == CTCM_PROTO_MPC) || | |
154 | (value == CTCM_PROTO_OS390))) | |
155 | return -EINVAL; | |
156 | priv->protocol = value; | |
157 | CTCM_DBF_DEV(SETUP, dev, buf); | |
158 | ||
159 | return count; | |
160 | } | |
161 | ||
0ca8cc6f UB |
162 | const char *ctcm_type[] = { |
163 | "not a channel", | |
164 | "CTC/A", | |
165 | "FICON channel", | |
166 | "ESCON channel", | |
167 | "unknown channel type", | |
168 | "unsupported channel type", | |
169 | }; | |
170 | ||
293d984f PT |
171 | static ssize_t ctcm_type_show(struct device *dev, |
172 | struct device_attribute *attr, char *buf) | |
173 | { | |
174 | struct ccwgroup_device *cgdev; | |
175 | ||
176 | cgdev = to_ccwgroupdev(dev); | |
177 | if (!cgdev) | |
178 | return -ENODEV; | |
179 | ||
180 | return sprintf(buf, "%s\n", | |
0ca8cc6f | 181 | ctcm_type[cgdev->cdev[0]->id.driver_info]); |
293d984f PT |
182 | } |
183 | ||
184 | static DEVICE_ATTR(buffer, 0644, ctcm_buffer_show, ctcm_buffer_write); | |
185 | static DEVICE_ATTR(protocol, 0644, ctcm_proto_show, ctcm_proto_store); | |
186 | static DEVICE_ATTR(type, 0444, ctcm_type_show, NULL); | |
187 | static DEVICE_ATTR(stats, 0644, stats_show, stats_write); | |
188 | ||
189 | static struct attribute *ctcm_attr[] = { | |
190 | &dev_attr_protocol.attr, | |
191 | &dev_attr_type.attr, | |
192 | &dev_attr_buffer.attr, | |
193 | NULL, | |
194 | }; | |
195 | ||
196 | static struct attribute_group ctcm_attr_group = { | |
197 | .attrs = ctcm_attr, | |
198 | }; | |
199 | ||
200 | int ctcm_add_attributes(struct device *dev) | |
201 | { | |
202 | int rc; | |
203 | ||
204 | rc = device_create_file(dev, &dev_attr_stats); | |
205 | ||
206 | return rc; | |
207 | } | |
208 | ||
209 | void ctcm_remove_attributes(struct device *dev) | |
210 | { | |
211 | device_remove_file(dev, &dev_attr_stats); | |
212 | } | |
213 | ||
214 | int ctcm_add_files(struct device *dev) | |
215 | { | |
216 | return sysfs_create_group(&dev->kobj, &ctcm_attr_group); | |
217 | } | |
218 | ||
219 | void ctcm_remove_files(struct device *dev) | |
220 | { | |
221 | sysfs_remove_group(&dev->kobj, &ctcm_attr_group); | |
222 | } | |
223 |