]>
Commit | Line | Data |
---|---|---|
4a71df50 | 1 | /* |
4a71df50 FB |
2 | * Copyright IBM Corp. 2007 |
3 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | |
4 | * Frank Pavlic <fpavlic@de.ibm.com>, | |
5 | * Thomas Spatzier <tspat@de.ibm.com>, | |
6 | * Frank Blaschka <frank.blaschka@de.ibm.com> | |
7 | */ | |
8 | ||
fe7a2625 UB |
9 | #define KMSG_COMPONENT "qeth" |
10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
11 | ||
4a71df50 FB |
12 | #include <linux/list.h> |
13 | #include <linux/rwsem.h> | |
14 | #include <asm/ebcdic.h> | |
15 | ||
16 | #include "qeth_core.h" | |
17 | ||
18 | static ssize_t qeth_dev_state_show(struct device *dev, | |
19 | struct device_attribute *attr, char *buf) | |
20 | { | |
21 | struct qeth_card *card = dev_get_drvdata(dev); | |
22 | if (!card) | |
23 | return -EINVAL; | |
24 | ||
25 | switch (card->state) { | |
26 | case CARD_STATE_DOWN: | |
27 | return sprintf(buf, "DOWN\n"); | |
28 | case CARD_STATE_HARDSETUP: | |
29 | return sprintf(buf, "HARDSETUP\n"); | |
30 | case CARD_STATE_SOFTSETUP: | |
31 | return sprintf(buf, "SOFTSETUP\n"); | |
32 | case CARD_STATE_UP: | |
33 | if (card->lan_online) | |
34 | return sprintf(buf, "UP (LAN ONLINE)\n"); | |
35 | else | |
36 | return sprintf(buf, "UP (LAN OFFLINE)\n"); | |
37 | case CARD_STATE_RECOVER: | |
38 | return sprintf(buf, "RECOVER\n"); | |
39 | default: | |
40 | return sprintf(buf, "UNKNOWN\n"); | |
41 | } | |
42 | } | |
43 | ||
44 | static DEVICE_ATTR(state, 0444, qeth_dev_state_show, NULL); | |
45 | ||
46 | static ssize_t qeth_dev_chpid_show(struct device *dev, | |
47 | struct device_attribute *attr, char *buf) | |
48 | { | |
49 | struct qeth_card *card = dev_get_drvdata(dev); | |
50 | if (!card) | |
51 | return -EINVAL; | |
52 | ||
53 | return sprintf(buf, "%02X\n", card->info.chpid); | |
54 | } | |
55 | ||
56 | static DEVICE_ATTR(chpid, 0444, qeth_dev_chpid_show, NULL); | |
57 | ||
58 | static ssize_t qeth_dev_if_name_show(struct device *dev, | |
59 | struct device_attribute *attr, char *buf) | |
60 | { | |
61 | struct qeth_card *card = dev_get_drvdata(dev); | |
62 | if (!card) | |
63 | return -EINVAL; | |
64 | return sprintf(buf, "%s\n", QETH_CARD_IFNAME(card)); | |
65 | } | |
66 | ||
67 | static DEVICE_ATTR(if_name, 0444, qeth_dev_if_name_show, NULL); | |
68 | ||
69 | static ssize_t qeth_dev_card_type_show(struct device *dev, | |
70 | struct device_attribute *attr, char *buf) | |
71 | { | |
72 | struct qeth_card *card = dev_get_drvdata(dev); | |
73 | if (!card) | |
74 | return -EINVAL; | |
75 | ||
76 | return sprintf(buf, "%s\n", qeth_get_cardname_short(card)); | |
77 | } | |
78 | ||
79 | static DEVICE_ATTR(card_type, 0444, qeth_dev_card_type_show, NULL); | |
80 | ||
81 | static inline const char *qeth_get_bufsize_str(struct qeth_card *card) | |
82 | { | |
83 | if (card->qdio.in_buf_size == 16384) | |
84 | return "16k"; | |
85 | else if (card->qdio.in_buf_size == 24576) | |
86 | return "24k"; | |
87 | else if (card->qdio.in_buf_size == 32768) | |
88 | return "32k"; | |
89 | else if (card->qdio.in_buf_size == 40960) | |
90 | return "40k"; | |
91 | else | |
92 | return "64k"; | |
93 | } | |
94 | ||
95 | static ssize_t qeth_dev_inbuf_size_show(struct device *dev, | |
96 | struct device_attribute *attr, char *buf) | |
97 | { | |
98 | struct qeth_card *card = dev_get_drvdata(dev); | |
99 | if (!card) | |
100 | return -EINVAL; | |
101 | ||
102 | return sprintf(buf, "%s\n", qeth_get_bufsize_str(card)); | |
103 | } | |
104 | ||
105 | static DEVICE_ATTR(inbuf_size, 0444, qeth_dev_inbuf_size_show, NULL); | |
106 | ||
107 | static ssize_t qeth_dev_portno_show(struct device *dev, | |
108 | struct device_attribute *attr, char *buf) | |
109 | { | |
110 | struct qeth_card *card = dev_get_drvdata(dev); | |
111 | if (!card) | |
112 | return -EINVAL; | |
113 | ||
114 | return sprintf(buf, "%i\n", card->info.portno); | |
115 | } | |
116 | ||
117 | static ssize_t qeth_dev_portno_store(struct device *dev, | |
118 | struct device_attribute *attr, const char *buf, size_t count) | |
119 | { | |
120 | struct qeth_card *card = dev_get_drvdata(dev); | |
121 | char *tmp; | |
76b11f8e | 122 | unsigned int portno, limit; |
c4949f07 | 123 | int rc = 0; |
4a71df50 FB |
124 | |
125 | if (!card) | |
126 | return -EINVAL; | |
127 | ||
c4949f07 | 128 | mutex_lock(&card->conf_mutex); |
4a71df50 | 129 | if ((card->state != CARD_STATE_DOWN) && |
c4949f07 FB |
130 | (card->state != CARD_STATE_RECOVER)) { |
131 | rc = -EPERM; | |
132 | goto out; | |
133 | } | |
4a71df50 FB |
134 | |
135 | portno = simple_strtoul(buf, &tmp, 16); | |
c4949f07 FB |
136 | if (portno > QETH_MAX_PORTNO) { |
137 | rc = -EINVAL; | |
138 | goto out; | |
139 | } | |
76b11f8e | 140 | limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt); |
c4949f07 FB |
141 | if (portno > limit) { |
142 | rc = -EINVAL; | |
143 | goto out; | |
144 | } | |
4a71df50 | 145 | card->info.portno = portno; |
c4949f07 FB |
146 | out: |
147 | mutex_unlock(&card->conf_mutex); | |
148 | return rc ? rc : count; | |
4a71df50 FB |
149 | } |
150 | ||
151 | static DEVICE_ATTR(portno, 0644, qeth_dev_portno_show, qeth_dev_portno_store); | |
152 | ||
153 | static ssize_t qeth_dev_portname_show(struct device *dev, | |
154 | struct device_attribute *attr, char *buf) | |
155 | { | |
239ff408 | 156 | return sprintf(buf, "no portname required\n"); |
4a71df50 FB |
157 | } |
158 | ||
159 | static ssize_t qeth_dev_portname_store(struct device *dev, | |
160 | struct device_attribute *attr, const char *buf, size_t count) | |
161 | { | |
162 | struct qeth_card *card = dev_get_drvdata(dev); | |
4a71df50 | 163 | |
239ff408 UB |
164 | dev_warn_once(&card->gdev->dev, |
165 | "portname is deprecated and is ignored\n"); | |
166 | return count; | |
4a71df50 FB |
167 | } |
168 | ||
169 | static DEVICE_ATTR(portname, 0644, qeth_dev_portname_show, | |
170 | qeth_dev_portname_store); | |
171 | ||
172 | static ssize_t qeth_dev_prioqing_show(struct device *dev, | |
173 | struct device_attribute *attr, char *buf) | |
174 | { | |
175 | struct qeth_card *card = dev_get_drvdata(dev); | |
176 | ||
177 | if (!card) | |
178 | return -EINVAL; | |
179 | ||
180 | switch (card->qdio.do_prio_queueing) { | |
181 | case QETH_PRIO_Q_ING_PREC: | |
182 | return sprintf(buf, "%s\n", "by precedence"); | |
183 | case QETH_PRIO_Q_ING_TOS: | |
184 | return sprintf(buf, "%s\n", "by type of service"); | |
d66cb37e SR |
185 | case QETH_PRIO_Q_ING_SKB: |
186 | return sprintf(buf, "%s\n", "by skb-priority"); | |
187 | case QETH_PRIO_Q_ING_VLAN: | |
188 | return sprintf(buf, "%s\n", "by VLAN headers"); | |
4a71df50 FB |
189 | default: |
190 | return sprintf(buf, "always queue %i\n", | |
191 | card->qdio.default_out_queue); | |
192 | } | |
193 | } | |
194 | ||
195 | static ssize_t qeth_dev_prioqing_store(struct device *dev, | |
196 | struct device_attribute *attr, const char *buf, size_t count) | |
197 | { | |
198 | struct qeth_card *card = dev_get_drvdata(dev); | |
c4949f07 | 199 | int rc = 0; |
4a71df50 FB |
200 | |
201 | if (!card) | |
202 | return -EINVAL; | |
203 | ||
c4949f07 | 204 | mutex_lock(&card->conf_mutex); |
4a71df50 | 205 | if ((card->state != CARD_STATE_DOWN) && |
c4949f07 FB |
206 | (card->state != CARD_STATE_RECOVER)) { |
207 | rc = -EPERM; | |
208 | goto out; | |
209 | } | |
4a71df50 FB |
210 | |
211 | /* check if 1920 devices are supported , | |
212 | * if though we have to permit priority queueing | |
213 | */ | |
214 | if (card->qdio.no_out_queues == 1) { | |
4a71df50 | 215 | card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; |
c4949f07 FB |
216 | rc = -EPERM; |
217 | goto out; | |
4a71df50 FB |
218 | } |
219 | ||
7e846d6b | 220 | if (sysfs_streq(buf, "prio_queueing_prec")) { |
4a71df50 | 221 | card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC; |
0f8ee7fc | 222 | card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; |
7e846d6b | 223 | } else if (sysfs_streq(buf, "prio_queueing_skb")) { |
d66cb37e SR |
224 | card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_SKB; |
225 | card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; | |
7e846d6b | 226 | } else if (sysfs_streq(buf, "prio_queueing_tos")) { |
4a71df50 | 227 | card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS; |
0f8ee7fc | 228 | card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; |
7e846d6b | 229 | } else if (sysfs_streq(buf, "prio_queueing_vlan")) { |
d66cb37e SR |
230 | if (!card->options.layer2) { |
231 | rc = -ENOTSUPP; | |
232 | goto out; | |
233 | } | |
234 | card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_VLAN; | |
235 | card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; | |
7e846d6b | 236 | } else if (sysfs_streq(buf, "no_prio_queueing:0")) { |
4a71df50 FB |
237 | card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; |
238 | card->qdio.default_out_queue = 0; | |
7e846d6b | 239 | } else if (sysfs_streq(buf, "no_prio_queueing:1")) { |
4a71df50 FB |
240 | card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; |
241 | card->qdio.default_out_queue = 1; | |
7e846d6b | 242 | } else if (sysfs_streq(buf, "no_prio_queueing:2")) { |
4a71df50 FB |
243 | card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; |
244 | card->qdio.default_out_queue = 2; | |
7e846d6b | 245 | } else if (sysfs_streq(buf, "no_prio_queueing:3")) { |
70deb016 HW |
246 | if (card->info.type == QETH_CARD_TYPE_IQD) { |
247 | rc = -EPERM; | |
248 | goto out; | |
249 | } | |
4a71df50 FB |
250 | card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; |
251 | card->qdio.default_out_queue = 3; | |
7e846d6b | 252 | } else if (sysfs_streq(buf, "no_prio_queueing")) { |
4a71df50 FB |
253 | card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; |
254 | card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; | |
c4949f07 FB |
255 | } else |
256 | rc = -EINVAL; | |
257 | out: | |
258 | mutex_unlock(&card->conf_mutex); | |
259 | return rc ? rc : count; | |
4a71df50 FB |
260 | } |
261 | ||
262 | static DEVICE_ATTR(priority_queueing, 0644, qeth_dev_prioqing_show, | |
263 | qeth_dev_prioqing_store); | |
264 | ||
265 | static ssize_t qeth_dev_bufcnt_show(struct device *dev, | |
266 | struct device_attribute *attr, char *buf) | |
267 | { | |
268 | struct qeth_card *card = dev_get_drvdata(dev); | |
269 | ||
270 | if (!card) | |
271 | return -EINVAL; | |
272 | ||
273 | return sprintf(buf, "%i\n", card->qdio.in_buf_pool.buf_count); | |
274 | } | |
275 | ||
276 | static ssize_t qeth_dev_bufcnt_store(struct device *dev, | |
277 | struct device_attribute *attr, const char *buf, size_t count) | |
278 | { | |
279 | struct qeth_card *card = dev_get_drvdata(dev); | |
280 | char *tmp; | |
281 | int cnt, old_cnt; | |
c4949f07 | 282 | int rc = 0; |
4a71df50 FB |
283 | |
284 | if (!card) | |
285 | return -EINVAL; | |
286 | ||
c4949f07 | 287 | mutex_lock(&card->conf_mutex); |
4a71df50 | 288 | if ((card->state != CARD_STATE_DOWN) && |
c4949f07 FB |
289 | (card->state != CARD_STATE_RECOVER)) { |
290 | rc = -EPERM; | |
291 | goto out; | |
292 | } | |
4a71df50 FB |
293 | |
294 | old_cnt = card->qdio.in_buf_pool.buf_count; | |
295 | cnt = simple_strtoul(buf, &tmp, 10); | |
296 | cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN : | |
297 | ((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt); | |
298 | if (old_cnt != cnt) { | |
299 | rc = qeth_realloc_buffer_pool(card, cnt); | |
4a71df50 | 300 | } |
c4949f07 FB |
301 | out: |
302 | mutex_unlock(&card->conf_mutex); | |
303 | return rc ? rc : count; | |
4a71df50 FB |
304 | } |
305 | ||
306 | static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show, | |
307 | qeth_dev_bufcnt_store); | |
308 | ||
309 | static ssize_t qeth_dev_recover_store(struct device *dev, | |
310 | struct device_attribute *attr, const char *buf, size_t count) | |
311 | { | |
312 | struct qeth_card *card = dev_get_drvdata(dev); | |
313 | char *tmp; | |
314 | int i; | |
315 | ||
316 | if (!card) | |
317 | return -EINVAL; | |
318 | ||
319 | if (card->state != CARD_STATE_UP) | |
320 | return -EPERM; | |
321 | ||
322 | i = simple_strtoul(buf, &tmp, 16); | |
323 | if (i == 1) | |
324 | qeth_schedule_recovery(card); | |
325 | ||
326 | return count; | |
327 | } | |
328 | ||
329 | static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store); | |
330 | ||
331 | static ssize_t qeth_dev_performance_stats_show(struct device *dev, | |
332 | struct device_attribute *attr, char *buf) | |
333 | { | |
334 | struct qeth_card *card = dev_get_drvdata(dev); | |
335 | ||
336 | if (!card) | |
337 | return -EINVAL; | |
338 | ||
339 | return sprintf(buf, "%i\n", card->options.performance_stats ? 1:0); | |
340 | } | |
341 | ||
342 | static ssize_t qeth_dev_performance_stats_store(struct device *dev, | |
343 | struct device_attribute *attr, const char *buf, size_t count) | |
344 | { | |
345 | struct qeth_card *card = dev_get_drvdata(dev); | |
346 | char *tmp; | |
c4949f07 | 347 | int i, rc = 0; |
4a71df50 FB |
348 | |
349 | if (!card) | |
350 | return -EINVAL; | |
351 | ||
c4949f07 | 352 | mutex_lock(&card->conf_mutex); |
4a71df50 FB |
353 | i = simple_strtoul(buf, &tmp, 16); |
354 | if ((i == 0) || (i == 1)) { | |
355 | if (i == card->options.performance_stats) | |
cdac082e | 356 | goto out; |
4a71df50 FB |
357 | card->options.performance_stats = i; |
358 | if (i == 0) | |
359 | memset(&card->perf_stats, 0, | |
360 | sizeof(struct qeth_perf_stats)); | |
361 | card->perf_stats.initial_rx_packets = card->stats.rx_packets; | |
362 | card->perf_stats.initial_tx_packets = card->stats.tx_packets; | |
c4949f07 FB |
363 | } else |
364 | rc = -EINVAL; | |
365 | out: | |
366 | mutex_unlock(&card->conf_mutex); | |
367 | return rc ? rc : count; | |
4a71df50 FB |
368 | } |
369 | ||
370 | static DEVICE_ATTR(performance_stats, 0644, qeth_dev_performance_stats_show, | |
371 | qeth_dev_performance_stats_store); | |
372 | ||
373 | static ssize_t qeth_dev_layer2_show(struct device *dev, | |
374 | struct device_attribute *attr, char *buf) | |
375 | { | |
376 | struct qeth_card *card = dev_get_drvdata(dev); | |
377 | ||
378 | if (!card) | |
379 | return -EINVAL; | |
380 | ||
7c6a3ed5 | 381 | return sprintf(buf, "%i\n", card->options.layer2); |
4a71df50 FB |
382 | } |
383 | ||
384 | static ssize_t qeth_dev_layer2_store(struct device *dev, | |
385 | struct device_attribute *attr, const char *buf, size_t count) | |
386 | { | |
387 | struct qeth_card *card = dev_get_drvdata(dev); | |
388 | char *tmp; | |
c4949f07 | 389 | int i, rc = 0; |
4a71df50 FB |
390 | enum qeth_discipline_id newdis; |
391 | ||
392 | if (!card) | |
393 | return -EINVAL; | |
394 | ||
9dc48ccc | 395 | mutex_lock(&card->discipline_mutex); |
c4949f07 FB |
396 | if (card->state != CARD_STATE_DOWN) { |
397 | rc = -EPERM; | |
398 | goto out; | |
399 | } | |
4a71df50 FB |
400 | |
401 | i = simple_strtoul(buf, &tmp, 16); | |
402 | switch (i) { | |
403 | case 0: | |
404 | newdis = QETH_DISCIPLINE_LAYER3; | |
405 | break; | |
406 | case 1: | |
407 | newdis = QETH_DISCIPLINE_LAYER2; | |
408 | break; | |
409 | default: | |
c4949f07 FB |
410 | rc = -EINVAL; |
411 | goto out; | |
4a71df50 FB |
412 | } |
413 | ||
c4949f07 FB |
414 | if (card->options.layer2 == newdis) |
415 | goto out; | |
416 | else { | |
75e0de13 | 417 | card->info.mac_bits = 0; |
c041f2d4 SO |
418 | if (card->discipline) { |
419 | card->discipline->remove(card->gdev); | |
4a71df50 FB |
420 | qeth_core_free_discipline(card); |
421 | } | |
422 | } | |
423 | ||
424 | rc = qeth_core_load_discipline(card, newdis); | |
425 | if (rc) | |
c4949f07 | 426 | goto out; |
4a71df50 | 427 | |
c041f2d4 | 428 | rc = card->discipline->setup(card->gdev); |
c4949f07 | 429 | out: |
9dc48ccc | 430 | mutex_unlock(&card->discipline_mutex); |
c4949f07 | 431 | return rc ? rc : count; |
4a71df50 FB |
432 | } |
433 | ||
434 | static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show, | |
435 | qeth_dev_layer2_store); | |
436 | ||
d64ecc22 EL |
437 | #define ATTR_QETH_ISOLATION_NONE ("none") |
438 | #define ATTR_QETH_ISOLATION_FWD ("forward") | |
439 | #define ATTR_QETH_ISOLATION_DROP ("drop") | |
440 | ||
441 | static ssize_t qeth_dev_isolation_show(struct device *dev, | |
442 | struct device_attribute *attr, char *buf) | |
443 | { | |
444 | struct qeth_card *card = dev_get_drvdata(dev); | |
445 | ||
446 | if (!card) | |
447 | return -EINVAL; | |
448 | ||
449 | switch (card->options.isolation) { | |
450 | case ISOLATION_MODE_NONE: | |
451 | return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_NONE); | |
452 | case ISOLATION_MODE_FWD: | |
453 | return snprintf(buf, 9, "%s\n", ATTR_QETH_ISOLATION_FWD); | |
454 | case ISOLATION_MODE_DROP: | |
455 | return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_DROP); | |
456 | default: | |
457 | return snprintf(buf, 5, "%s\n", "N/A"); | |
458 | } | |
459 | } | |
460 | ||
461 | static ssize_t qeth_dev_isolation_store(struct device *dev, | |
462 | struct device_attribute *attr, const char *buf, size_t count) | |
463 | { | |
464 | struct qeth_card *card = dev_get_drvdata(dev); | |
465 | enum qeth_ipa_isolation_modes isolation; | |
466 | int rc = 0; | |
d64ecc22 | 467 | |
c4949f07 FB |
468 | if (!card) |
469 | return -EINVAL; | |
d64ecc22 | 470 | |
c4949f07 | 471 | mutex_lock(&card->conf_mutex); |
d64ecc22 | 472 | /* check for unknown, too, in case we do not yet know who we are */ |
5113fec0 UB |
473 | if (card->info.type != QETH_CARD_TYPE_OSD && |
474 | card->info.type != QETH_CARD_TYPE_OSX && | |
d64ecc22 EL |
475 | card->info.type != QETH_CARD_TYPE_UNKNOWN) { |
476 | rc = -EOPNOTSUPP; | |
477 | dev_err(&card->gdev->dev, "Adapter does not " | |
478 | "support QDIO data connection isolation\n"); | |
479 | goto out; | |
480 | } | |
481 | ||
482 | /* parse input into isolation mode */ | |
7e846d6b | 483 | if (sysfs_streq(buf, ATTR_QETH_ISOLATION_NONE)) { |
d64ecc22 | 484 | isolation = ISOLATION_MODE_NONE; |
7e846d6b | 485 | } else if (sysfs_streq(buf, ATTR_QETH_ISOLATION_FWD)) { |
d64ecc22 | 486 | isolation = ISOLATION_MODE_FWD; |
7e846d6b | 487 | } else if (sysfs_streq(buf, ATTR_QETH_ISOLATION_DROP)) { |
d64ecc22 EL |
488 | isolation = ISOLATION_MODE_DROP; |
489 | } else { | |
490 | rc = -EINVAL; | |
491 | goto out; | |
492 | } | |
493 | rc = count; | |
494 | ||
495 | /* defer IP assist if device is offline (until discipline->set_online)*/ | |
0f54761d | 496 | card->options.prev_isolation = card->options.isolation; |
d64ecc22 | 497 | card->options.isolation = isolation; |
c3521254 | 498 | if (qeth_card_hw_is_reachable(card)) { |
0f54761d | 499 | int ipa_rc = qeth_set_access_ctrl_online(card, 1); |
d64ecc22 EL |
500 | if (ipa_rc != 0) |
501 | rc = ipa_rc; | |
502 | } | |
503 | out: | |
c4949f07 | 504 | mutex_unlock(&card->conf_mutex); |
d64ecc22 EL |
505 | return rc; |
506 | } | |
507 | ||
508 | static DEVICE_ATTR(isolation, 0644, qeth_dev_isolation_show, | |
45cbb2e4 SR |
509 | qeth_dev_isolation_store); |
510 | ||
511 | static ssize_t qeth_dev_switch_attrs_show(struct device *dev, | |
512 | struct device_attribute *attr, char *buf) | |
513 | { | |
514 | struct qeth_card *card = dev_get_drvdata(dev); | |
515 | struct qeth_switch_info sw_info; | |
516 | int rc = 0; | |
517 | ||
518 | if (!card) | |
519 | return -EINVAL; | |
520 | ||
c3521254 | 521 | if (!qeth_card_hw_is_reachable(card)) |
45cbb2e4 SR |
522 | return sprintf(buf, "n/a\n"); |
523 | ||
524 | rc = qeth_query_switch_attributes(card, &sw_info); | |
525 | if (rc) | |
526 | return rc; | |
527 | ||
528 | if (!sw_info.capabilities) | |
529 | rc = sprintf(buf, "unknown"); | |
530 | ||
531 | if (sw_info.capabilities & QETH_SWITCH_FORW_802_1) | |
532 | rc = sprintf(buf, (sw_info.settings & QETH_SWITCH_FORW_802_1 ? | |
533 | "[802.1]" : "802.1")); | |
534 | if (sw_info.capabilities & QETH_SWITCH_FORW_REFL_RELAY) | |
535 | rc += sprintf(buf + rc, | |
536 | (sw_info.settings & QETH_SWITCH_FORW_REFL_RELAY ? | |
537 | " [rr]" : " rr")); | |
538 | rc += sprintf(buf + rc, "\n"); | |
539 | ||
540 | return rc; | |
541 | } | |
542 | ||
543 | static DEVICE_ATTR(switch_attrs, 0444, | |
544 | qeth_dev_switch_attrs_show, NULL); | |
d64ecc22 | 545 | |
1da74b1c FB |
546 | static ssize_t qeth_hw_trap_show(struct device *dev, |
547 | struct device_attribute *attr, char *buf) | |
548 | { | |
549 | struct qeth_card *card = dev_get_drvdata(dev); | |
550 | ||
551 | if (!card) | |
552 | return -EINVAL; | |
553 | if (card->info.hwtrap) | |
554 | return snprintf(buf, 5, "arm\n"); | |
555 | else | |
556 | return snprintf(buf, 8, "disarm\n"); | |
557 | } | |
558 | ||
559 | static ssize_t qeth_hw_trap_store(struct device *dev, | |
560 | struct device_attribute *attr, const char *buf, size_t count) | |
561 | { | |
562 | struct qeth_card *card = dev_get_drvdata(dev); | |
563 | int rc = 0; | |
1da74b1c | 564 | int state = 0; |
1da74b1c FB |
565 | |
566 | if (!card) | |
567 | return -EINVAL; | |
568 | ||
569 | mutex_lock(&card->conf_mutex); | |
c3521254 | 570 | if (qeth_card_hw_is_reachable(card)) |
1da74b1c | 571 | state = 1; |
1da74b1c | 572 | |
7e846d6b | 573 | if (sysfs_streq(buf, "arm") && !card->info.hwtrap) { |
1da74b1c FB |
574 | if (state) { |
575 | if (qeth_is_diagass_supported(card, | |
576 | QETH_DIAGS_CMD_TRAP)) { | |
577 | rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM); | |
578 | if (!rc) | |
579 | card->info.hwtrap = 1; | |
580 | } else | |
581 | rc = -EINVAL; | |
582 | } else | |
583 | card->info.hwtrap = 1; | |
7e846d6b | 584 | } else if (sysfs_streq(buf, "disarm") && card->info.hwtrap) { |
1da74b1c FB |
585 | if (state) { |
586 | rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); | |
587 | if (!rc) | |
588 | card->info.hwtrap = 0; | |
589 | } else | |
590 | card->info.hwtrap = 0; | |
7e846d6b | 591 | } else if (sysfs_streq(buf, "trap") && state && card->info.hwtrap) |
1da74b1c FB |
592 | rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_CAPTURE); |
593 | else | |
594 | rc = -EINVAL; | |
595 | ||
596 | mutex_unlock(&card->conf_mutex); | |
597 | return rc ? rc : count; | |
598 | } | |
599 | ||
600 | static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show, | |
601 | qeth_hw_trap_store); | |
602 | ||
4a71df50 FB |
603 | static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value) |
604 | { | |
605 | ||
606 | if (!card) | |
607 | return -EINVAL; | |
608 | ||
609 | return sprintf(buf, "%i\n", value); | |
610 | } | |
611 | ||
612 | static ssize_t qeth_dev_blkt_store(struct qeth_card *card, | |
613 | const char *buf, size_t count, int *value, int max_value) | |
614 | { | |
615 | char *tmp; | |
c4949f07 | 616 | int i, rc = 0; |
4a71df50 FB |
617 | |
618 | if (!card) | |
619 | return -EINVAL; | |
620 | ||
c4949f07 | 621 | mutex_lock(&card->conf_mutex); |
4a71df50 | 622 | if ((card->state != CARD_STATE_DOWN) && |
c4949f07 FB |
623 | (card->state != CARD_STATE_RECOVER)) { |
624 | rc = -EPERM; | |
625 | goto out; | |
626 | } | |
4a71df50 | 627 | i = simple_strtoul(buf, &tmp, 10); |
c4949f07 | 628 | if (i <= max_value) |
4a71df50 | 629 | *value = i; |
c4949f07 FB |
630 | else |
631 | rc = -EINVAL; | |
632 | out: | |
633 | mutex_unlock(&card->conf_mutex); | |
634 | return rc ? rc : count; | |
4a71df50 FB |
635 | } |
636 | ||
637 | static ssize_t qeth_dev_blkt_total_show(struct device *dev, | |
638 | struct device_attribute *attr, char *buf) | |
639 | { | |
640 | struct qeth_card *card = dev_get_drvdata(dev); | |
641 | ||
642 | return qeth_dev_blkt_show(buf, card, card->info.blkt.time_total); | |
643 | } | |
644 | ||
645 | static ssize_t qeth_dev_blkt_total_store(struct device *dev, | |
646 | struct device_attribute *attr, const char *buf, size_t count) | |
647 | { | |
648 | struct qeth_card *card = dev_get_drvdata(dev); | |
649 | ||
650 | return qeth_dev_blkt_store(card, buf, count, | |
a60389ab | 651 | &card->info.blkt.time_total, 5000); |
4a71df50 FB |
652 | } |
653 | ||
654 | ||
655 | ||
656 | static DEVICE_ATTR(total, 0644, qeth_dev_blkt_total_show, | |
657 | qeth_dev_blkt_total_store); | |
658 | ||
659 | static ssize_t qeth_dev_blkt_inter_show(struct device *dev, | |
660 | struct device_attribute *attr, char *buf) | |
661 | { | |
662 | struct qeth_card *card = dev_get_drvdata(dev); | |
663 | ||
664 | return qeth_dev_blkt_show(buf, card, card->info.blkt.inter_packet); | |
665 | } | |
666 | ||
667 | static ssize_t qeth_dev_blkt_inter_store(struct device *dev, | |
668 | struct device_attribute *attr, const char *buf, size_t count) | |
669 | { | |
670 | struct qeth_card *card = dev_get_drvdata(dev); | |
671 | ||
672 | return qeth_dev_blkt_store(card, buf, count, | |
a60389ab | 673 | &card->info.blkt.inter_packet, 1000); |
4a71df50 FB |
674 | } |
675 | ||
676 | static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show, | |
677 | qeth_dev_blkt_inter_store); | |
678 | ||
679 | static ssize_t qeth_dev_blkt_inter_jumbo_show(struct device *dev, | |
680 | struct device_attribute *attr, char *buf) | |
681 | { | |
682 | struct qeth_card *card = dev_get_drvdata(dev); | |
683 | ||
684 | return qeth_dev_blkt_show(buf, card, | |
685 | card->info.blkt.inter_packet_jumbo); | |
686 | } | |
687 | ||
688 | static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev, | |
689 | struct device_attribute *attr, const char *buf, size_t count) | |
690 | { | |
691 | struct qeth_card *card = dev_get_drvdata(dev); | |
692 | ||
693 | return qeth_dev_blkt_store(card, buf, count, | |
a60389ab | 694 | &card->info.blkt.inter_packet_jumbo, 1000); |
4a71df50 FB |
695 | } |
696 | ||
697 | static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show, | |
698 | qeth_dev_blkt_inter_jumbo_store); | |
699 | ||
700 | static struct attribute *qeth_blkt_device_attrs[] = { | |
701 | &dev_attr_total.attr, | |
702 | &dev_attr_inter.attr, | |
703 | &dev_attr_inter_jumbo.attr, | |
704 | NULL, | |
705 | }; | |
4a71df50 FB |
706 | static struct attribute_group qeth_device_blkt_group = { |
707 | .name = "blkt", | |
708 | .attrs = qeth_blkt_device_attrs, | |
709 | }; | |
710 | ||
711 | static struct attribute *qeth_device_attrs[] = { | |
712 | &dev_attr_state.attr, | |
713 | &dev_attr_chpid.attr, | |
714 | &dev_attr_if_name.attr, | |
715 | &dev_attr_card_type.attr, | |
716 | &dev_attr_inbuf_size.attr, | |
717 | &dev_attr_portno.attr, | |
718 | &dev_attr_portname.attr, | |
719 | &dev_attr_priority_queueing.attr, | |
720 | &dev_attr_buffer_count.attr, | |
721 | &dev_attr_recover.attr, | |
722 | &dev_attr_performance_stats.attr, | |
723 | &dev_attr_layer2.attr, | |
d64ecc22 | 724 | &dev_attr_isolation.attr, |
1da74b1c | 725 | &dev_attr_hw_trap.attr, |
45cbb2e4 | 726 | &dev_attr_switch_attrs.attr, |
4a71df50 FB |
727 | NULL, |
728 | }; | |
4a71df50 FB |
729 | static struct attribute_group qeth_device_attr_group = { |
730 | .attrs = qeth_device_attrs, | |
731 | }; | |
732 | ||
b7169c51 SO |
733 | const struct attribute_group *qeth_generic_attr_groups[] = { |
734 | &qeth_device_attr_group, | |
735 | &qeth_device_blkt_group, | |
736 | NULL, | |
737 | }; | |
738 | ||
4a71df50 FB |
739 | static struct attribute *qeth_osn_device_attrs[] = { |
740 | &dev_attr_state.attr, | |
741 | &dev_attr_chpid.attr, | |
742 | &dev_attr_if_name.attr, | |
743 | &dev_attr_card_type.attr, | |
744 | &dev_attr_buffer_count.attr, | |
745 | &dev_attr_recover.attr, | |
746 | NULL, | |
747 | }; | |
4a71df50 FB |
748 | static struct attribute_group qeth_osn_device_attr_group = { |
749 | .attrs = qeth_osn_device_attrs, | |
750 | }; | |
b7169c51 SO |
751 | const struct attribute_group *qeth_osn_attr_groups[] = { |
752 | &qeth_osn_device_attr_group, | |
753 | NULL, | |
754 | }; |