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