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