diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/s390/net/lcs.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/s390/net/lcs.c')
-rw-r--r-- | drivers/s390/net/lcs.c | 2347 |
1 files changed, 2347 insertions, 0 deletions
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c new file mode 100644 index 000000000000..0f76e945b984 --- /dev/null +++ b/drivers/s390/net/lcs.c | |||
@@ -0,0 +1,2347 @@ | |||
1 | /* | ||
2 | * linux/drivers/s390/net/lcs.c | ||
3 | * | ||
4 | * Linux for S/390 Lan Channel Station Network Driver | ||
5 | * | ||
6 | * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, | ||
7 | * IBM Corporation | ||
8 | * Author(s): Original Code written by | ||
9 | * DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) | ||
10 | * Rewritten by | ||
11 | * Frank Pavlic (pavlic@de.ibm.com) and | ||
12 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
13 | * | ||
14 | * $Revision: 1.96 $ $Date: 2004/11/11 13:42:33 $ | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2, or (at your option) | ||
19 | * any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | #include <linux/if.h> | ||
33 | #include <linux/netdevice.h> | ||
34 | #include <linux/etherdevice.h> | ||
35 | #include <linux/trdevice.h> | ||
36 | #include <linux/fddidevice.h> | ||
37 | #include <linux/inetdevice.h> | ||
38 | #include <linux/in.h> | ||
39 | #include <linux/igmp.h> | ||
40 | #include <linux/delay.h> | ||
41 | #include <net/arp.h> | ||
42 | #include <net/ip.h> | ||
43 | |||
44 | #include <asm/debug.h> | ||
45 | #include <asm/idals.h> | ||
46 | #include <asm/timex.h> | ||
47 | #include <linux/device.h> | ||
48 | #include <asm/ccwgroup.h> | ||
49 | |||
50 | #include "lcs.h" | ||
51 | #include "cu3088.h" | ||
52 | |||
53 | |||
54 | #if !defined(CONFIG_NET_ETHERNET) && \ | ||
55 | !defined(CONFIG_TR) && !defined(CONFIG_FDDI) | ||
56 | #error Cannot compile lcs.c without some net devices switched on. | ||
57 | #endif | ||
58 | |||
59 | /** | ||
60 | * initialization string for output | ||
61 | */ | ||
62 | #define VERSION_LCS_C "$Revision: 1.96 $" | ||
63 | |||
64 | static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; | ||
65 | static char debug_buffer[255]; | ||
66 | |||
67 | /** | ||
68 | * Some prototypes. | ||
69 | */ | ||
70 | static void lcs_tasklet(unsigned long); | ||
71 | static void lcs_start_kernel_thread(struct lcs_card *card); | ||
72 | static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *); | ||
73 | static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *); | ||
74 | |||
75 | /** | ||
76 | * Debug Facility Stuff | ||
77 | */ | ||
78 | static debug_info_t *lcs_dbf_setup; | ||
79 | static debug_info_t *lcs_dbf_trace; | ||
80 | |||
81 | /** | ||
82 | * LCS Debug Facility functions | ||
83 | */ | ||
84 | static void | ||
85 | lcs_unregister_debug_facility(void) | ||
86 | { | ||
87 | if (lcs_dbf_setup) | ||
88 | debug_unregister(lcs_dbf_setup); | ||
89 | if (lcs_dbf_trace) | ||
90 | debug_unregister(lcs_dbf_trace); | ||
91 | } | ||
92 | |||
93 | static int | ||
94 | lcs_register_debug_facility(void) | ||
95 | { | ||
96 | lcs_dbf_setup = debug_register("lcs_setup", 1, 1, 8); | ||
97 | lcs_dbf_trace = debug_register("lcs_trace", 1, 2, 8); | ||
98 | if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) { | ||
99 | PRINT_ERR("Not enough memory for debug facility.\n"); | ||
100 | lcs_unregister_debug_facility(); | ||
101 | return -ENOMEM; | ||
102 | } | ||
103 | debug_register_view(lcs_dbf_setup, &debug_hex_ascii_view); | ||
104 | debug_set_level(lcs_dbf_setup, 4); | ||
105 | debug_register_view(lcs_dbf_trace, &debug_hex_ascii_view); | ||
106 | debug_set_level(lcs_dbf_trace, 4); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * Allocate io buffers. | ||
112 | */ | ||
113 | static int | ||
114 | lcs_alloc_channel(struct lcs_channel *channel) | ||
115 | { | ||
116 | int cnt; | ||
117 | |||
118 | LCS_DBF_TEXT(2, setup, "ichalloc"); | ||
119 | for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) { | ||
120 | /* alloc memory fo iobuffer */ | ||
121 | channel->iob[cnt].data = (void *) | ||
122 | kmalloc(LCS_IOBUFFERSIZE, GFP_DMA | GFP_KERNEL); | ||
123 | if (channel->iob[cnt].data == NULL) | ||
124 | break; | ||
125 | memset(channel->iob[cnt].data, 0, LCS_IOBUFFERSIZE); | ||
126 | channel->iob[cnt].state = BUF_STATE_EMPTY; | ||
127 | } | ||
128 | if (cnt < LCS_NUM_BUFFS) { | ||
129 | /* Not all io buffers could be allocated. */ | ||
130 | LCS_DBF_TEXT(2, setup, "echalloc"); | ||
131 | while (cnt-- > 0) | ||
132 | kfree(channel->iob[cnt].data); | ||
133 | return -ENOMEM; | ||
134 | } | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * Free io buffers. | ||
140 | */ | ||
141 | static void | ||
142 | lcs_free_channel(struct lcs_channel *channel) | ||
143 | { | ||
144 | int cnt; | ||
145 | |||
146 | LCS_DBF_TEXT(2, setup, "ichfree"); | ||
147 | for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) { | ||
148 | if (channel->iob[cnt].data != NULL) | ||
149 | kfree(channel->iob[cnt].data); | ||
150 | channel->iob[cnt].data = NULL; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Cleanup channel. | ||
156 | */ | ||
157 | static void | ||
158 | lcs_cleanup_channel(struct lcs_channel *channel) | ||
159 | { | ||
160 | LCS_DBF_TEXT(3, setup, "cleanch"); | ||
161 | /* Kill write channel tasklets. */ | ||
162 | tasklet_kill(&channel->irq_tasklet); | ||
163 | /* Free channel buffers. */ | ||
164 | lcs_free_channel(channel); | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * LCS free memory for card and channels. | ||
169 | */ | ||
170 | static void | ||
171 | lcs_free_card(struct lcs_card *card) | ||
172 | { | ||
173 | LCS_DBF_TEXT(2, setup, "remcard"); | ||
174 | LCS_DBF_HEX(2, setup, &card, sizeof(void*)); | ||
175 | kfree(card); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * LCS alloc memory for card and channels | ||
180 | */ | ||
181 | static struct lcs_card * | ||
182 | lcs_alloc_card(void) | ||
183 | { | ||
184 | struct lcs_card *card; | ||
185 | int rc; | ||
186 | |||
187 | LCS_DBF_TEXT(2, setup, "alloclcs"); | ||
188 | |||
189 | card = kmalloc(sizeof(struct lcs_card), GFP_KERNEL | GFP_DMA); | ||
190 | if (card == NULL) | ||
191 | return NULL; | ||
192 | memset(card, 0, sizeof(struct lcs_card)); | ||
193 | card->lan_type = LCS_FRAME_TYPE_AUTO; | ||
194 | card->pkt_seq = 0; | ||
195 | card->lancmd_timeout = LCS_LANCMD_TIMEOUT_DEFAULT; | ||
196 | /* Allocate io buffers for the read channel. */ | ||
197 | rc = lcs_alloc_channel(&card->read); | ||
198 | if (rc){ | ||
199 | LCS_DBF_TEXT(2, setup, "iccwerr"); | ||
200 | lcs_free_card(card); | ||
201 | return NULL; | ||
202 | } | ||
203 | /* Allocate io buffers for the write channel. */ | ||
204 | rc = lcs_alloc_channel(&card->write); | ||
205 | if (rc) { | ||
206 | LCS_DBF_TEXT(2, setup, "iccwerr"); | ||
207 | lcs_cleanup_channel(&card->read); | ||
208 | lcs_free_card(card); | ||
209 | return NULL; | ||
210 | } | ||
211 | |||
212 | #ifdef CONFIG_IP_MULTICAST | ||
213 | INIT_LIST_HEAD(&card->ipm_list); | ||
214 | #endif | ||
215 | LCS_DBF_HEX(2, setup, &card, sizeof(void*)); | ||
216 | return card; | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Setup read channel. | ||
221 | */ | ||
222 | static void | ||
223 | lcs_setup_read_ccws(struct lcs_card *card) | ||
224 | { | ||
225 | int cnt; | ||
226 | |||
227 | LCS_DBF_TEXT(2, setup, "ireadccw"); | ||
228 | /* Setup read ccws. */ | ||
229 | memset(card->read.ccws, 0, sizeof (struct ccw1) * (LCS_NUM_BUFFS + 1)); | ||
230 | for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) { | ||
231 | card->read.ccws[cnt].cmd_code = LCS_CCW_READ; | ||
232 | card->read.ccws[cnt].count = LCS_IOBUFFERSIZE; | ||
233 | card->read.ccws[cnt].flags = | ||
234 | CCW_FLAG_CC | CCW_FLAG_SLI | CCW_FLAG_PCI; | ||
235 | /* | ||
236 | * Note: we have allocated the buffer with GFP_DMA, so | ||
237 | * we do not need to do set_normalized_cda. | ||
238 | */ | ||
239 | card->read.ccws[cnt].cda = | ||
240 | (__u32) __pa(card->read.iob[cnt].data); | ||
241 | ((struct lcs_header *) | ||
242 | card->read.iob[cnt].data)->offset = LCS_ILLEGAL_OFFSET; | ||
243 | card->read.iob[cnt].callback = lcs_get_frames_cb; | ||
244 | card->read.iob[cnt].state = BUF_STATE_READY; | ||
245 | card->read.iob[cnt].count = LCS_IOBUFFERSIZE; | ||
246 | } | ||
247 | card->read.ccws[0].flags &= ~CCW_FLAG_PCI; | ||
248 | card->read.ccws[LCS_NUM_BUFFS - 1].flags &= ~CCW_FLAG_PCI; | ||
249 | card->read.ccws[LCS_NUM_BUFFS - 1].flags |= CCW_FLAG_SUSPEND; | ||
250 | /* Last ccw is a tic (transfer in channel). */ | ||
251 | card->read.ccws[LCS_NUM_BUFFS].cmd_code = LCS_CCW_TRANSFER; | ||
252 | card->read.ccws[LCS_NUM_BUFFS].cda = | ||
253 | (__u32) __pa(card->read.ccws); | ||
254 | /* Setg initial state of the read channel. */ | ||
255 | card->read.state = CH_STATE_INIT; | ||
256 | |||
257 | card->read.io_idx = 0; | ||
258 | card->read.buf_idx = 0; | ||
259 | } | ||
260 | |||
261 | static void | ||
262 | lcs_setup_read(struct lcs_card *card) | ||
263 | { | ||
264 | LCS_DBF_TEXT(3, setup, "initread"); | ||
265 | |||
266 | lcs_setup_read_ccws(card); | ||
267 | /* Initialize read channel tasklet. */ | ||
268 | card->read.irq_tasklet.data = (unsigned long) &card->read; | ||
269 | card->read.irq_tasklet.func = lcs_tasklet; | ||
270 | /* Initialize waitqueue. */ | ||
271 | init_waitqueue_head(&card->read.wait_q); | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * Setup write channel. | ||
276 | */ | ||
277 | static void | ||
278 | lcs_setup_write_ccws(struct lcs_card *card) | ||
279 | { | ||
280 | int cnt; | ||
281 | |||
282 | LCS_DBF_TEXT(3, setup, "iwritccw"); | ||
283 | /* Setup write ccws. */ | ||
284 | memset(card->write.ccws, 0, sizeof(struct ccw1) * LCS_NUM_BUFFS + 1); | ||
285 | for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) { | ||
286 | card->write.ccws[cnt].cmd_code = LCS_CCW_WRITE; | ||
287 | card->write.ccws[cnt].count = 0; | ||
288 | card->write.ccws[cnt].flags = | ||
289 | CCW_FLAG_SUSPEND | CCW_FLAG_CC | CCW_FLAG_SLI; | ||
290 | /* | ||
291 | * Note: we have allocated the buffer with GFP_DMA, so | ||
292 | * we do not need to do set_normalized_cda. | ||
293 | */ | ||
294 | card->write.ccws[cnt].cda = | ||
295 | (__u32) __pa(card->write.iob[cnt].data); | ||
296 | } | ||
297 | /* Last ccw is a tic (transfer in channel). */ | ||
298 | card->write.ccws[LCS_NUM_BUFFS].cmd_code = LCS_CCW_TRANSFER; | ||
299 | card->write.ccws[LCS_NUM_BUFFS].cda = | ||
300 | (__u32) __pa(card->write.ccws); | ||
301 | /* Set initial state of the write channel. */ | ||
302 | card->read.state = CH_STATE_INIT; | ||
303 | |||
304 | card->write.io_idx = 0; | ||
305 | card->write.buf_idx = 0; | ||
306 | } | ||
307 | |||
308 | static void | ||
309 | lcs_setup_write(struct lcs_card *card) | ||
310 | { | ||
311 | LCS_DBF_TEXT(3, setup, "initwrit"); | ||
312 | |||
313 | lcs_setup_write_ccws(card); | ||
314 | /* Initialize write channel tasklet. */ | ||
315 | card->write.irq_tasklet.data = (unsigned long) &card->write; | ||
316 | card->write.irq_tasklet.func = lcs_tasklet; | ||
317 | /* Initialize waitqueue. */ | ||
318 | init_waitqueue_head(&card->write.wait_q); | ||
319 | } | ||
320 | |||
321 | static void | ||
322 | lcs_set_allowed_threads(struct lcs_card *card, unsigned long threads) | ||
323 | { | ||
324 | unsigned long flags; | ||
325 | |||
326 | spin_lock_irqsave(&card->mask_lock, flags); | ||
327 | card->thread_allowed_mask = threads; | ||
328 | spin_unlock_irqrestore(&card->mask_lock, flags); | ||
329 | wake_up(&card->wait_q); | ||
330 | } | ||
331 | static inline int | ||
332 | lcs_threads_running(struct lcs_card *card, unsigned long threads) | ||
333 | { | ||
334 | unsigned long flags; | ||
335 | int rc = 0; | ||
336 | |||
337 | spin_lock_irqsave(&card->mask_lock, flags); | ||
338 | rc = (card->thread_running_mask & threads); | ||
339 | spin_unlock_irqrestore(&card->mask_lock, flags); | ||
340 | return rc; | ||
341 | } | ||
342 | |||
343 | static int | ||
344 | lcs_wait_for_threads(struct lcs_card *card, unsigned long threads) | ||
345 | { | ||
346 | return wait_event_interruptible(card->wait_q, | ||
347 | lcs_threads_running(card, threads) == 0); | ||
348 | } | ||
349 | |||
350 | static inline int | ||
351 | lcs_set_thread_start_bit(struct lcs_card *card, unsigned long thread) | ||
352 | { | ||
353 | unsigned long flags; | ||
354 | |||
355 | spin_lock_irqsave(&card->mask_lock, flags); | ||
356 | if ( !(card->thread_allowed_mask & thread) || | ||
357 | (card->thread_start_mask & thread) ) { | ||
358 | spin_unlock_irqrestore(&card->mask_lock, flags); | ||
359 | return -EPERM; | ||
360 | } | ||
361 | card->thread_start_mask |= thread; | ||
362 | spin_unlock_irqrestore(&card->mask_lock, flags); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static void | ||
367 | lcs_clear_thread_running_bit(struct lcs_card *card, unsigned long thread) | ||
368 | { | ||
369 | unsigned long flags; | ||
370 | |||
371 | spin_lock_irqsave(&card->mask_lock, flags); | ||
372 | card->thread_running_mask &= ~thread; | ||
373 | spin_unlock_irqrestore(&card->mask_lock, flags); | ||
374 | wake_up(&card->wait_q); | ||
375 | } | ||
376 | |||
377 | static inline int | ||
378 | __lcs_do_run_thread(struct lcs_card *card, unsigned long thread) | ||
379 | { | ||
380 | unsigned long flags; | ||
381 | int rc = 0; | ||
382 | |||
383 | spin_lock_irqsave(&card->mask_lock, flags); | ||
384 | if (card->thread_start_mask & thread){ | ||
385 | if ((card->thread_allowed_mask & thread) && | ||
386 | !(card->thread_running_mask & thread)){ | ||
387 | rc = 1; | ||
388 | card->thread_start_mask &= ~thread; | ||
389 | card->thread_running_mask |= thread; | ||
390 | } else | ||
391 | rc = -EPERM; | ||
392 | } | ||
393 | spin_unlock_irqrestore(&card->mask_lock, flags); | ||
394 | return rc; | ||
395 | } | ||
396 | |||
397 | static int | ||
398 | lcs_do_run_thread(struct lcs_card *card, unsigned long thread) | ||
399 | { | ||
400 | int rc = 0; | ||
401 | wait_event(card->wait_q, | ||
402 | (rc = __lcs_do_run_thread(card, thread)) >= 0); | ||
403 | return rc; | ||
404 | } | ||
405 | |||
406 | static int | ||
407 | lcs_do_start_thread(struct lcs_card *card, unsigned long thread) | ||
408 | { | ||
409 | unsigned long flags; | ||
410 | int rc = 0; | ||
411 | |||
412 | spin_lock_irqsave(&card->mask_lock, flags); | ||
413 | LCS_DBF_TEXT_(4, trace, " %02x%02x%02x", | ||
414 | (u8) card->thread_start_mask, | ||
415 | (u8) card->thread_allowed_mask, | ||
416 | (u8) card->thread_running_mask); | ||
417 | rc = (card->thread_start_mask & thread); | ||
418 | spin_unlock_irqrestore(&card->mask_lock, flags); | ||
419 | return rc; | ||
420 | } | ||
421 | |||
422 | /** | ||
423 | * Initialize channels,card and state machines. | ||
424 | */ | ||
425 | static void | ||
426 | lcs_setup_card(struct lcs_card *card) | ||
427 | { | ||
428 | LCS_DBF_TEXT(2, setup, "initcard"); | ||
429 | LCS_DBF_HEX(2, setup, &card, sizeof(void*)); | ||
430 | |||
431 | lcs_setup_read(card); | ||
432 | lcs_setup_write(card); | ||
433 | /* Set cards initial state. */ | ||
434 | card->state = DEV_STATE_DOWN; | ||
435 | card->tx_buffer = NULL; | ||
436 | card->tx_emitted = 0; | ||
437 | |||
438 | /* Initialize kernel thread task used for LGW commands. */ | ||
439 | INIT_WORK(&card->kernel_thread_starter, | ||
440 | (void *)lcs_start_kernel_thread,card); | ||
441 | card->thread_start_mask = 0; | ||
442 | card->thread_allowed_mask = 0; | ||
443 | card->thread_running_mask = 0; | ||
444 | init_waitqueue_head(&card->wait_q); | ||
445 | spin_lock_init(&card->lock); | ||
446 | spin_lock_init(&card->ipm_lock); | ||
447 | spin_lock_init(&card->mask_lock); | ||
448 | #ifdef CONFIG_IP_MULTICAST | ||
449 | INIT_LIST_HEAD(&card->ipm_list); | ||
450 | #endif | ||
451 | INIT_LIST_HEAD(&card->lancmd_waiters); | ||
452 | } | ||
453 | |||
454 | static inline void | ||
455 | lcs_clear_multicast_list(struct lcs_card *card) | ||
456 | { | ||
457 | #ifdef CONFIG_IP_MULTICAST | ||
458 | struct lcs_ipm_list *ipm; | ||
459 | unsigned long flags; | ||
460 | |||
461 | /* Free multicast list. */ | ||
462 | LCS_DBF_TEXT(3, setup, "clmclist"); | ||
463 | spin_lock_irqsave(&card->ipm_lock, flags); | ||
464 | while (!list_empty(&card->ipm_list)){ | ||
465 | ipm = list_entry(card->ipm_list.next, | ||
466 | struct lcs_ipm_list, list); | ||
467 | list_del(&ipm->list); | ||
468 | if (ipm->ipm_state != LCS_IPM_STATE_SET_REQUIRED){ | ||
469 | spin_unlock_irqrestore(&card->ipm_lock, flags); | ||
470 | lcs_send_delipm(card, ipm); | ||
471 | spin_lock_irqsave(&card->ipm_lock, flags); | ||
472 | } | ||
473 | kfree(ipm); | ||
474 | } | ||
475 | spin_unlock_irqrestore(&card->ipm_lock, flags); | ||
476 | #endif | ||
477 | } | ||
478 | /** | ||
479 | * Cleanup channels,card and state machines. | ||
480 | */ | ||
481 | static void | ||
482 | lcs_cleanup_card(struct lcs_card *card) | ||
483 | { | ||
484 | |||
485 | LCS_DBF_TEXT(3, setup, "cleancrd"); | ||
486 | LCS_DBF_HEX(2,setup,&card,sizeof(void*)); | ||
487 | |||
488 | if (card->dev != NULL) | ||
489 | free_netdev(card->dev); | ||
490 | /* Cleanup channels. */ | ||
491 | lcs_cleanup_channel(&card->write); | ||
492 | lcs_cleanup_channel(&card->read); | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * Start channel. | ||
497 | */ | ||
498 | static int | ||
499 | lcs_start_channel(struct lcs_channel *channel) | ||
500 | { | ||
501 | unsigned long flags; | ||
502 | int rc; | ||
503 | |||
504 | LCS_DBF_TEXT_(4,trace,"ssch%s", channel->ccwdev->dev.bus_id); | ||
505 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | ||
506 | rc = ccw_device_start(channel->ccwdev, | ||
507 | channel->ccws + channel->io_idx, 0, 0, | ||
508 | DOIO_DENY_PREFETCH | DOIO_ALLOW_SUSPEND); | ||
509 | if (rc == 0) | ||
510 | channel->state = CH_STATE_RUNNING; | ||
511 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | ||
512 | if (rc) { | ||
513 | LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id); | ||
514 | PRINT_ERR("Error in starting channel, rc=%d!\n", rc); | ||
515 | } | ||
516 | return rc; | ||
517 | } | ||
518 | |||
519 | static int | ||
520 | lcs_clear_channel(struct lcs_channel *channel) | ||
521 | { | ||
522 | unsigned long flags; | ||
523 | int rc; | ||
524 | |||
525 | LCS_DBF_TEXT(4,trace,"clearch"); | ||
526 | LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); | ||
527 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | ||
528 | rc = ccw_device_clear(channel->ccwdev, (addr_t) channel); | ||
529 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | ||
530 | if (rc) { | ||
531 | LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id); | ||
532 | return rc; | ||
533 | } | ||
534 | wait_event(channel->wait_q, (channel->state == CH_STATE_CLEARED)); | ||
535 | channel->state = CH_STATE_STOPPED; | ||
536 | return rc; | ||
537 | } | ||
538 | |||
539 | |||
540 | /** | ||
541 | * Stop channel. | ||
542 | */ | ||
543 | static int | ||
544 | lcs_stop_channel(struct lcs_channel *channel) | ||
545 | { | ||
546 | unsigned long flags; | ||
547 | int rc; | ||
548 | |||
549 | if (channel->state == CH_STATE_STOPPED) | ||
550 | return 0; | ||
551 | LCS_DBF_TEXT(4,trace,"haltsch"); | ||
552 | LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id); | ||
553 | channel->state = CH_STATE_INIT; | ||
554 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | ||
555 | rc = ccw_device_halt(channel->ccwdev, (addr_t) channel); | ||
556 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | ||
557 | if (rc) { | ||
558 | LCS_DBF_TEXT_(4,trace,"ehsc%s", channel->ccwdev->dev.bus_id); | ||
559 | return rc; | ||
560 | } | ||
561 | /* Asynchronous halt initialted. Wait for its completion. */ | ||
562 | wait_event(channel->wait_q, (channel->state == CH_STATE_HALTED)); | ||
563 | lcs_clear_channel(channel); | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * start read and write channel | ||
569 | */ | ||
570 | static int | ||
571 | lcs_start_channels(struct lcs_card *card) | ||
572 | { | ||
573 | int rc; | ||
574 | |||
575 | LCS_DBF_TEXT(2, trace, "chstart"); | ||
576 | /* start read channel */ | ||
577 | rc = lcs_start_channel(&card->read); | ||
578 | if (rc) | ||
579 | return rc; | ||
580 | /* start write channel */ | ||
581 | rc = lcs_start_channel(&card->write); | ||
582 | if (rc) | ||
583 | lcs_stop_channel(&card->read); | ||
584 | return rc; | ||
585 | } | ||
586 | |||
587 | /** | ||
588 | * stop read and write channel | ||
589 | */ | ||
590 | static int | ||
591 | lcs_stop_channels(struct lcs_card *card) | ||
592 | { | ||
593 | LCS_DBF_TEXT(2, trace, "chhalt"); | ||
594 | lcs_stop_channel(&card->read); | ||
595 | lcs_stop_channel(&card->write); | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | /** | ||
600 | * Get empty buffer. | ||
601 | */ | ||
602 | static struct lcs_buffer * | ||
603 | __lcs_get_buffer(struct lcs_channel *channel) | ||
604 | { | ||
605 | int index; | ||
606 | |||
607 | LCS_DBF_TEXT(5, trace, "_getbuff"); | ||
608 | index = channel->io_idx; | ||
609 | do { | ||
610 | if (channel->iob[index].state == BUF_STATE_EMPTY) { | ||
611 | channel->iob[index].state = BUF_STATE_LOCKED; | ||
612 | return channel->iob + index; | ||
613 | } | ||
614 | index = (index + 1) & (LCS_NUM_BUFFS - 1); | ||
615 | } while (index != channel->io_idx); | ||
616 | return NULL; | ||
617 | } | ||
618 | |||
619 | static struct lcs_buffer * | ||
620 | lcs_get_buffer(struct lcs_channel *channel) | ||
621 | { | ||
622 | struct lcs_buffer *buffer; | ||
623 | unsigned long flags; | ||
624 | |||
625 | LCS_DBF_TEXT(5, trace, "getbuff"); | ||
626 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | ||
627 | buffer = __lcs_get_buffer(channel); | ||
628 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | ||
629 | return buffer; | ||
630 | } | ||
631 | |||
632 | /** | ||
633 | * Resume channel program if the channel is suspended. | ||
634 | */ | ||
635 | static int | ||
636 | __lcs_resume_channel(struct lcs_channel *channel) | ||
637 | { | ||
638 | int rc; | ||
639 | |||
640 | if (channel->state != CH_STATE_SUSPENDED) | ||
641 | return 0; | ||
642 | if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND) | ||
643 | return 0; | ||
644 | LCS_DBF_TEXT_(5, trace, "rsch%s", channel->ccwdev->dev.bus_id); | ||
645 | rc = ccw_device_resume(channel->ccwdev); | ||
646 | if (rc) { | ||
647 | LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id); | ||
648 | PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); | ||
649 | } else | ||
650 | channel->state = CH_STATE_RUNNING; | ||
651 | return rc; | ||
652 | |||
653 | } | ||
654 | |||
655 | /** | ||
656 | * Make a buffer ready for processing. | ||
657 | */ | ||
658 | static inline void | ||
659 | __lcs_ready_buffer_bits(struct lcs_channel *channel, int index) | ||
660 | { | ||
661 | int prev, next; | ||
662 | |||
663 | LCS_DBF_TEXT(5, trace, "rdybits"); | ||
664 | prev = (index - 1) & (LCS_NUM_BUFFS - 1); | ||
665 | next = (index + 1) & (LCS_NUM_BUFFS - 1); | ||
666 | /* Check if we may clear the suspend bit of this buffer. */ | ||
667 | if (channel->ccws[next].flags & CCW_FLAG_SUSPEND) { | ||
668 | /* Check if we have to set the PCI bit. */ | ||
669 | if (!(channel->ccws[prev].flags & CCW_FLAG_SUSPEND)) | ||
670 | /* Suspend bit of the previous buffer is not set. */ | ||
671 | channel->ccws[index].flags |= CCW_FLAG_PCI; | ||
672 | /* Suspend bit of the next buffer is set. */ | ||
673 | channel->ccws[index].flags &= ~CCW_FLAG_SUSPEND; | ||
674 | } | ||
675 | } | ||
676 | |||
677 | static int | ||
678 | lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | ||
679 | { | ||
680 | unsigned long flags; | ||
681 | int index, rc; | ||
682 | |||
683 | LCS_DBF_TEXT(5, trace, "rdybuff"); | ||
684 | if (buffer->state != BUF_STATE_LOCKED && | ||
685 | buffer->state != BUF_STATE_PROCESSED) | ||
686 | BUG(); | ||
687 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | ||
688 | buffer->state = BUF_STATE_READY; | ||
689 | index = buffer - channel->iob; | ||
690 | /* Set length. */ | ||
691 | channel->ccws[index].count = buffer->count; | ||
692 | /* Check relevant PCI/suspend bits. */ | ||
693 | __lcs_ready_buffer_bits(channel, index); | ||
694 | rc = __lcs_resume_channel(channel); | ||
695 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | ||
696 | return rc; | ||
697 | } | ||
698 | |||
699 | /** | ||
700 | * Mark the buffer as processed. Take care of the suspend bit | ||
701 | * of the previous buffer. This function is called from | ||
702 | * interrupt context, so the lock must not be taken. | ||
703 | */ | ||
704 | static int | ||
705 | __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | ||
706 | { | ||
707 | int index, prev, next; | ||
708 | |||
709 | LCS_DBF_TEXT(5, trace, "prcsbuff"); | ||
710 | if (buffer->state != BUF_STATE_READY) | ||
711 | BUG(); | ||
712 | buffer->state = BUF_STATE_PROCESSED; | ||
713 | index = buffer - channel->iob; | ||
714 | prev = (index - 1) & (LCS_NUM_BUFFS - 1); | ||
715 | next = (index + 1) & (LCS_NUM_BUFFS - 1); | ||
716 | /* Set the suspend bit and clear the PCI bit of this buffer. */ | ||
717 | channel->ccws[index].flags |= CCW_FLAG_SUSPEND; | ||
718 | channel->ccws[index].flags &= ~CCW_FLAG_PCI; | ||
719 | /* Check the suspend bit of the previous buffer. */ | ||
720 | if (channel->iob[prev].state == BUF_STATE_READY) { | ||
721 | /* | ||
722 | * Previous buffer is in state ready. It might have | ||
723 | * happened in lcs_ready_buffer that the suspend bit | ||
724 | * has not been cleared to avoid an endless loop. | ||
725 | * Do it now. | ||
726 | */ | ||
727 | __lcs_ready_buffer_bits(channel, prev); | ||
728 | } | ||
729 | /* Clear PCI bit of next buffer. */ | ||
730 | channel->ccws[next].flags &= ~CCW_FLAG_PCI; | ||
731 | return __lcs_resume_channel(channel); | ||
732 | } | ||
733 | |||
734 | /** | ||
735 | * Put a processed buffer back to state empty. | ||
736 | */ | ||
737 | static void | ||
738 | lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | ||
739 | { | ||
740 | unsigned long flags; | ||
741 | |||
742 | LCS_DBF_TEXT(5, trace, "relbuff"); | ||
743 | if (buffer->state != BUF_STATE_LOCKED && | ||
744 | buffer->state != BUF_STATE_PROCESSED) | ||
745 | BUG(); | ||
746 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | ||
747 | buffer->state = BUF_STATE_EMPTY; | ||
748 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | ||
749 | } | ||
750 | |||
751 | /** | ||
752 | * Get buffer for a lan command. | ||
753 | */ | ||
754 | static struct lcs_buffer * | ||
755 | lcs_get_lancmd(struct lcs_card *card, int count) | ||
756 | { | ||
757 | struct lcs_buffer *buffer; | ||
758 | struct lcs_cmd *cmd; | ||
759 | |||
760 | LCS_DBF_TEXT(4, trace, "getlncmd"); | ||
761 | /* Get buffer and wait if none is available. */ | ||
762 | wait_event(card->write.wait_q, | ||
763 | ((buffer = lcs_get_buffer(&card->write)) != NULL)); | ||
764 | count += sizeof(struct lcs_header); | ||
765 | *(__u16 *)(buffer->data + count) = 0; | ||
766 | buffer->count = count + sizeof(__u16); | ||
767 | buffer->callback = lcs_release_buffer; | ||
768 | cmd = (struct lcs_cmd *) buffer->data; | ||
769 | cmd->offset = count; | ||
770 | cmd->type = LCS_FRAME_TYPE_CONTROL; | ||
771 | cmd->slot = 0; | ||
772 | return buffer; | ||
773 | } | ||
774 | |||
775 | |||
776 | static void | ||
777 | lcs_get_reply(struct lcs_reply *reply) | ||
778 | { | ||
779 | WARN_ON(atomic_read(&reply->refcnt) <= 0); | ||
780 | atomic_inc(&reply->refcnt); | ||
781 | } | ||
782 | |||
783 | static void | ||
784 | lcs_put_reply(struct lcs_reply *reply) | ||
785 | { | ||
786 | WARN_ON(atomic_read(&reply->refcnt) <= 0); | ||
787 | if (atomic_dec_and_test(&reply->refcnt)) { | ||
788 | kfree(reply); | ||
789 | } | ||
790 | |||
791 | } | ||
792 | |||
793 | static struct lcs_reply * | ||
794 | lcs_alloc_reply(struct lcs_cmd *cmd) | ||
795 | { | ||
796 | struct lcs_reply *reply; | ||
797 | |||
798 | LCS_DBF_TEXT(4, trace, "getreply"); | ||
799 | |||
800 | reply = kmalloc(sizeof(struct lcs_reply), GFP_ATOMIC); | ||
801 | if (!reply) | ||
802 | return NULL; | ||
803 | memset(reply,0,sizeof(struct lcs_reply)); | ||
804 | atomic_set(&reply->refcnt,1); | ||
805 | reply->sequence_no = cmd->sequence_no; | ||
806 | reply->received = 0; | ||
807 | reply->rc = 0; | ||
808 | init_waitqueue_head(&reply->wait_q); | ||
809 | |||
810 | return reply; | ||
811 | } | ||
812 | |||
813 | /** | ||
814 | * Notifier function for lancmd replies. Called from read irq. | ||
815 | */ | ||
816 | static void | ||
817 | lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd) | ||
818 | { | ||
819 | struct list_head *l, *n; | ||
820 | struct lcs_reply *reply; | ||
821 | |||
822 | LCS_DBF_TEXT(4, trace, "notiwait"); | ||
823 | spin_lock(&card->lock); | ||
824 | list_for_each_safe(l, n, &card->lancmd_waiters) { | ||
825 | reply = list_entry(l, struct lcs_reply, list); | ||
826 | if (reply->sequence_no == cmd->sequence_no) { | ||
827 | lcs_get_reply(reply); | ||
828 | list_del_init(&reply->list); | ||
829 | if (reply->callback != NULL) | ||
830 | reply->callback(card, cmd); | ||
831 | reply->received = 1; | ||
832 | reply->rc = cmd->return_code; | ||
833 | wake_up(&reply->wait_q); | ||
834 | lcs_put_reply(reply); | ||
835 | break; | ||
836 | } | ||
837 | } | ||
838 | spin_unlock(&card->lock); | ||
839 | } | ||
840 | |||
841 | /** | ||
842 | * Emit buffer of a lan comand. | ||
843 | */ | ||
844 | void | ||
845 | lcs_lancmd_timeout(unsigned long data) | ||
846 | { | ||
847 | struct lcs_reply *reply, *list_reply, *r; | ||
848 | unsigned long flags; | ||
849 | |||
850 | LCS_DBF_TEXT(4, trace, "timeout"); | ||
851 | reply = (struct lcs_reply *) data; | ||
852 | spin_lock_irqsave(&reply->card->lock, flags); | ||
853 | list_for_each_entry_safe(list_reply, r, | ||
854 | &reply->card->lancmd_waiters,list) { | ||
855 | if (reply == list_reply) { | ||
856 | lcs_get_reply(reply); | ||
857 | list_del_init(&reply->list); | ||
858 | spin_unlock_irqrestore(&reply->card->lock, flags); | ||
859 | reply->received = 1; | ||
860 | reply->rc = -ETIME; | ||
861 | wake_up(&reply->wait_q); | ||
862 | lcs_put_reply(reply); | ||
863 | return; | ||
864 | } | ||
865 | } | ||
866 | spin_unlock_irqrestore(&reply->card->lock, flags); | ||
867 | } | ||
868 | |||
869 | static int | ||
870 | lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer, | ||
871 | void (*reply_callback)(struct lcs_card *, struct lcs_cmd *)) | ||
872 | { | ||
873 | struct lcs_reply *reply; | ||
874 | struct lcs_cmd *cmd; | ||
875 | struct timer_list timer; | ||
876 | unsigned long flags; | ||
877 | int rc; | ||
878 | |||
879 | LCS_DBF_TEXT(4, trace, "sendcmd"); | ||
880 | cmd = (struct lcs_cmd *) buffer->data; | ||
881 | cmd->return_code = 0; | ||
882 | cmd->sequence_no = card->sequence_no++; | ||
883 | reply = lcs_alloc_reply(cmd); | ||
884 | if (!reply) | ||
885 | return -ENOMEM; | ||
886 | reply->callback = reply_callback; | ||
887 | reply->card = card; | ||
888 | spin_lock_irqsave(&card->lock, flags); | ||
889 | list_add_tail(&reply->list, &card->lancmd_waiters); | ||
890 | spin_unlock_irqrestore(&card->lock, flags); | ||
891 | |||
892 | buffer->callback = lcs_release_buffer; | ||
893 | rc = lcs_ready_buffer(&card->write, buffer); | ||
894 | if (rc) | ||
895 | return rc; | ||
896 | init_timer(&timer); | ||
897 | timer.function = lcs_lancmd_timeout; | ||
898 | timer.data = (unsigned long) reply; | ||
899 | timer.expires = jiffies + HZ*card->lancmd_timeout; | ||
900 | add_timer(&timer); | ||
901 | wait_event(reply->wait_q, reply->received); | ||
902 | del_timer_sync(&timer); | ||
903 | LCS_DBF_TEXT_(4, trace, "rc:%d",reply->rc); | ||
904 | rc = reply->rc; | ||
905 | lcs_put_reply(reply); | ||
906 | return rc ? -EIO : 0; | ||
907 | } | ||
908 | |||
909 | /** | ||
910 | * LCS startup command | ||
911 | */ | ||
912 | static int | ||
913 | lcs_send_startup(struct lcs_card *card, __u8 initiator) | ||
914 | { | ||
915 | struct lcs_buffer *buffer; | ||
916 | struct lcs_cmd *cmd; | ||
917 | |||
918 | LCS_DBF_TEXT(2, trace, "startup"); | ||
919 | buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE); | ||
920 | cmd = (struct lcs_cmd *) buffer->data; | ||
921 | cmd->cmd_code = LCS_CMD_STARTUP; | ||
922 | cmd->initiator = initiator; | ||
923 | cmd->cmd.lcs_startup.buff_size = LCS_IOBUFFERSIZE; | ||
924 | return lcs_send_lancmd(card, buffer, NULL); | ||
925 | } | ||
926 | |||
927 | /** | ||
928 | * LCS shutdown command | ||
929 | */ | ||
930 | static int | ||
931 | lcs_send_shutdown(struct lcs_card *card) | ||
932 | { | ||
933 | struct lcs_buffer *buffer; | ||
934 | struct lcs_cmd *cmd; | ||
935 | |||
936 | LCS_DBF_TEXT(2, trace, "shutdown"); | ||
937 | buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE); | ||
938 | cmd = (struct lcs_cmd *) buffer->data; | ||
939 | cmd->cmd_code = LCS_CMD_SHUTDOWN; | ||
940 | cmd->initiator = LCS_INITIATOR_TCPIP; | ||
941 | return lcs_send_lancmd(card, buffer, NULL); | ||
942 | } | ||
943 | |||
944 | /** | ||
945 | * LCS lanstat command | ||
946 | */ | ||
947 | static void | ||
948 | __lcs_lanstat_cb(struct lcs_card *card, struct lcs_cmd *cmd) | ||
949 | { | ||
950 | LCS_DBF_TEXT(2, trace, "statcb"); | ||
951 | memcpy(card->mac, cmd->cmd.lcs_lanstat_cmd.mac_addr, LCS_MAC_LENGTH); | ||
952 | } | ||
953 | |||
954 | static int | ||
955 | lcs_send_lanstat(struct lcs_card *card) | ||
956 | { | ||
957 | struct lcs_buffer *buffer; | ||
958 | struct lcs_cmd *cmd; | ||
959 | |||
960 | LCS_DBF_TEXT(2,trace, "cmdstat"); | ||
961 | buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE); | ||
962 | cmd = (struct lcs_cmd *) buffer->data; | ||
963 | /* Setup lanstat command. */ | ||
964 | cmd->cmd_code = LCS_CMD_LANSTAT; | ||
965 | cmd->initiator = LCS_INITIATOR_TCPIP; | ||
966 | cmd->cmd.lcs_std_cmd.lan_type = card->lan_type; | ||
967 | cmd->cmd.lcs_std_cmd.portno = card->portno; | ||
968 | return lcs_send_lancmd(card, buffer, __lcs_lanstat_cb); | ||
969 | } | ||
970 | |||
971 | /** | ||
972 | * send stoplan command | ||
973 | */ | ||
974 | static int | ||
975 | lcs_send_stoplan(struct lcs_card *card, __u8 initiator) | ||
976 | { | ||
977 | struct lcs_buffer *buffer; | ||
978 | struct lcs_cmd *cmd; | ||
979 | |||
980 | LCS_DBF_TEXT(2, trace, "cmdstpln"); | ||
981 | buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE); | ||
982 | cmd = (struct lcs_cmd *) buffer->data; | ||
983 | cmd->cmd_code = LCS_CMD_STOPLAN; | ||
984 | cmd->initiator = initiator; | ||
985 | cmd->cmd.lcs_std_cmd.lan_type = card->lan_type; | ||
986 | cmd->cmd.lcs_std_cmd.portno = card->portno; | ||
987 | return lcs_send_lancmd(card, buffer, NULL); | ||
988 | } | ||
989 | |||
990 | /** | ||
991 | * send startlan command | ||
992 | */ | ||
993 | static void | ||
994 | __lcs_send_startlan_cb(struct lcs_card *card, struct lcs_cmd *cmd) | ||
995 | { | ||
996 | LCS_DBF_TEXT(2, trace, "srtlancb"); | ||
997 | card->lan_type = cmd->cmd.lcs_std_cmd.lan_type; | ||
998 | card->portno = cmd->cmd.lcs_std_cmd.portno; | ||
999 | } | ||
1000 | |||
1001 | static int | ||
1002 | lcs_send_startlan(struct lcs_card *card, __u8 initiator) | ||
1003 | { | ||
1004 | struct lcs_buffer *buffer; | ||
1005 | struct lcs_cmd *cmd; | ||
1006 | |||
1007 | LCS_DBF_TEXT(2, trace, "cmdstaln"); | ||
1008 | buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE); | ||
1009 | cmd = (struct lcs_cmd *) buffer->data; | ||
1010 | cmd->cmd_code = LCS_CMD_STARTLAN; | ||
1011 | cmd->initiator = initiator; | ||
1012 | cmd->cmd.lcs_std_cmd.lan_type = card->lan_type; | ||
1013 | cmd->cmd.lcs_std_cmd.portno = card->portno; | ||
1014 | return lcs_send_lancmd(card, buffer, __lcs_send_startlan_cb); | ||
1015 | } | ||
1016 | |||
1017 | #ifdef CONFIG_IP_MULTICAST | ||
1018 | /** | ||
1019 | * send setipm command (Multicast) | ||
1020 | */ | ||
1021 | static int | ||
1022 | lcs_send_setipm(struct lcs_card *card,struct lcs_ipm_list *ipm_list) | ||
1023 | { | ||
1024 | struct lcs_buffer *buffer; | ||
1025 | struct lcs_cmd *cmd; | ||
1026 | |||
1027 | LCS_DBF_TEXT(2, trace, "cmdsetim"); | ||
1028 | buffer = lcs_get_lancmd(card, LCS_MULTICAST_CMD_SIZE); | ||
1029 | cmd = (struct lcs_cmd *) buffer->data; | ||
1030 | cmd->cmd_code = LCS_CMD_SETIPM; | ||
1031 | cmd->initiator = LCS_INITIATOR_TCPIP; | ||
1032 | cmd->cmd.lcs_qipassist.lan_type = card->lan_type; | ||
1033 | cmd->cmd.lcs_qipassist.portno = card->portno; | ||
1034 | cmd->cmd.lcs_qipassist.version = 4; | ||
1035 | cmd->cmd.lcs_qipassist.num_ip_pairs = 1; | ||
1036 | memcpy(cmd->cmd.lcs_qipassist.lcs_ipass_ctlmsg.ip_mac_pair, | ||
1037 | &ipm_list->ipm, sizeof (struct lcs_ip_mac_pair)); | ||
1038 | LCS_DBF_TEXT_(2, trace, "%x",ipm_list->ipm.ip_addr); | ||
1039 | return lcs_send_lancmd(card, buffer, NULL); | ||
1040 | } | ||
1041 | |||
1042 | /** | ||
1043 | * send delipm command (Multicast) | ||
1044 | */ | ||
1045 | static int | ||
1046 | lcs_send_delipm(struct lcs_card *card,struct lcs_ipm_list *ipm_list) | ||
1047 | { | ||
1048 | struct lcs_buffer *buffer; | ||
1049 | struct lcs_cmd *cmd; | ||
1050 | |||
1051 | LCS_DBF_TEXT(2, trace, "cmddelim"); | ||
1052 | buffer = lcs_get_lancmd(card, LCS_MULTICAST_CMD_SIZE); | ||
1053 | cmd = (struct lcs_cmd *) buffer->data; | ||
1054 | cmd->cmd_code = LCS_CMD_DELIPM; | ||
1055 | cmd->initiator = LCS_INITIATOR_TCPIP; | ||
1056 | cmd->cmd.lcs_qipassist.lan_type = card->lan_type; | ||
1057 | cmd->cmd.lcs_qipassist.portno = card->portno; | ||
1058 | cmd->cmd.lcs_qipassist.version = 4; | ||
1059 | cmd->cmd.lcs_qipassist.num_ip_pairs = 1; | ||
1060 | memcpy(cmd->cmd.lcs_qipassist.lcs_ipass_ctlmsg.ip_mac_pair, | ||
1061 | &ipm_list->ipm, sizeof (struct lcs_ip_mac_pair)); | ||
1062 | LCS_DBF_TEXT_(2, trace, "%x",ipm_list->ipm.ip_addr); | ||
1063 | return lcs_send_lancmd(card, buffer, NULL); | ||
1064 | } | ||
1065 | |||
1066 | /** | ||
1067 | * check if multicast is supported by LCS | ||
1068 | */ | ||
1069 | static void | ||
1070 | __lcs_check_multicast_cb(struct lcs_card *card, struct lcs_cmd *cmd) | ||
1071 | { | ||
1072 | LCS_DBF_TEXT(2, trace, "chkmccb"); | ||
1073 | card->ip_assists_supported = | ||
1074 | cmd->cmd.lcs_qipassist.ip_assists_supported; | ||
1075 | card->ip_assists_enabled = | ||
1076 | cmd->cmd.lcs_qipassist.ip_assists_enabled; | ||
1077 | } | ||
1078 | |||
1079 | static int | ||
1080 | lcs_check_multicast_support(struct lcs_card *card) | ||
1081 | { | ||
1082 | struct lcs_buffer *buffer; | ||
1083 | struct lcs_cmd *cmd; | ||
1084 | int rc; | ||
1085 | |||
1086 | LCS_DBF_TEXT(2, trace, "cmdqipa"); | ||
1087 | /* Send query ipassist. */ | ||
1088 | buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE); | ||
1089 | cmd = (struct lcs_cmd *) buffer->data; | ||
1090 | cmd->cmd_code = LCS_CMD_QIPASSIST; | ||
1091 | cmd->initiator = LCS_INITIATOR_TCPIP; | ||
1092 | cmd->cmd.lcs_qipassist.lan_type = card->lan_type; | ||
1093 | cmd->cmd.lcs_qipassist.portno = card->portno; | ||
1094 | cmd->cmd.lcs_qipassist.version = 4; | ||
1095 | cmd->cmd.lcs_qipassist.num_ip_pairs = 1; | ||
1096 | rc = lcs_send_lancmd(card, buffer, __lcs_check_multicast_cb); | ||
1097 | if (rc != 0) { | ||
1098 | PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n"); | ||
1099 | return -EOPNOTSUPP; | ||
1100 | } | ||
1101 | /* Print out supported assists: IPv6 */ | ||
1102 | PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name, | ||
1103 | (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? | ||
1104 | "with" : "without"); | ||
1105 | /* Print out supported assist: Multicast */ | ||
1106 | PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name, | ||
1107 | (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? | ||
1108 | "with" : "without"); | ||
1109 | if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) | ||
1110 | return 0; | ||
1111 | return -EOPNOTSUPP; | ||
1112 | } | ||
1113 | |||
1114 | /** | ||
1115 | * set or del multicast address on LCS card | ||
1116 | */ | ||
1117 | static void | ||
1118 | lcs_fix_multicast_list(struct lcs_card *card) | ||
1119 | { | ||
1120 | struct list_head failed_list; | ||
1121 | struct lcs_ipm_list *ipm, *tmp; | ||
1122 | unsigned long flags; | ||
1123 | int rc; | ||
1124 | |||
1125 | LCS_DBF_TEXT(4,trace, "fixipm"); | ||
1126 | INIT_LIST_HEAD(&failed_list); | ||
1127 | spin_lock_irqsave(&card->ipm_lock, flags); | ||
1128 | list_modified: | ||
1129 | list_for_each_entry_safe(ipm, tmp, &card->ipm_list, list){ | ||
1130 | switch (ipm->ipm_state) { | ||
1131 | case LCS_IPM_STATE_SET_REQUIRED: | ||
1132 | /* del from ipm_list so noone else can tamper with | ||
1133 | * this entry */ | ||
1134 | list_del_init(&ipm->list); | ||
1135 | spin_unlock_irqrestore(&card->ipm_lock, flags); | ||
1136 | rc = lcs_send_setipm(card, ipm); | ||
1137 | spin_lock_irqsave(&card->ipm_lock, flags); | ||
1138 | if (rc) { | ||
1139 | PRINT_INFO("Adding multicast address failed." | ||
1140 | "Table possibly full!\n"); | ||
1141 | /* store ipm in failed list -> will be added | ||
1142 | * to ipm_list again, so a retry will be done | ||
1143 | * during the next call of this function */ | ||
1144 | list_add_tail(&ipm->list, &failed_list); | ||
1145 | } else { | ||
1146 | ipm->ipm_state = LCS_IPM_STATE_ON_CARD; | ||
1147 | /* re-insert into ipm_list */ | ||
1148 | list_add_tail(&ipm->list, &card->ipm_list); | ||
1149 | } | ||
1150 | goto list_modified; | ||
1151 | case LCS_IPM_STATE_DEL_REQUIRED: | ||
1152 | list_del(&ipm->list); | ||
1153 | spin_unlock_irqrestore(&card->ipm_lock, flags); | ||
1154 | lcs_send_delipm(card, ipm); | ||
1155 | spin_lock_irqsave(&card->ipm_lock, flags); | ||
1156 | kfree(ipm); | ||
1157 | goto list_modified; | ||
1158 | case LCS_IPM_STATE_ON_CARD: | ||
1159 | break; | ||
1160 | } | ||
1161 | } | ||
1162 | /* re-insert all entries from the failed_list into ipm_list */ | ||
1163 | list_for_each_entry(ipm, &failed_list, list) { | ||
1164 | list_del_init(&ipm->list); | ||
1165 | list_add_tail(&ipm->list, &card->ipm_list); | ||
1166 | } | ||
1167 | spin_unlock_irqrestore(&card->ipm_lock, flags); | ||
1168 | if (card->state == DEV_STATE_UP) | ||
1169 | netif_wake_queue(card->dev); | ||
1170 | } | ||
1171 | |||
1172 | /** | ||
1173 | * get mac address for the relevant Multicast address | ||
1174 | */ | ||
1175 | static void | ||
1176 | lcs_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev) | ||
1177 | { | ||
1178 | LCS_DBF_TEXT(4,trace, "getmac"); | ||
1179 | if (dev->type == ARPHRD_IEEE802_TR) | ||
1180 | ip_tr_mc_map(ipm, mac); | ||
1181 | else | ||
1182 | ip_eth_mc_map(ipm, mac); | ||
1183 | } | ||
1184 | |||
1185 | /** | ||
1186 | * function called by net device to handle multicast address relevant things | ||
1187 | */ | ||
1188 | static inline void | ||
1189 | lcs_remove_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) | ||
1190 | { | ||
1191 | struct ip_mc_list *im4; | ||
1192 | struct list_head *l; | ||
1193 | struct lcs_ipm_list *ipm; | ||
1194 | unsigned long flags; | ||
1195 | char buf[MAX_ADDR_LEN]; | ||
1196 | |||
1197 | LCS_DBF_TEXT(4, trace, "remmclst"); | ||
1198 | spin_lock_irqsave(&card->ipm_lock, flags); | ||
1199 | list_for_each(l, &card->ipm_list) { | ||
1200 | ipm = list_entry(l, struct lcs_ipm_list, list); | ||
1201 | for (im4 = in4_dev->mc_list; im4 != NULL; im4 = im4->next) { | ||
1202 | lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev); | ||
1203 | if ( (ipm->ipm.ip_addr == im4->multiaddr) && | ||
1204 | (memcmp(buf, &ipm->ipm.mac_addr, | ||
1205 | LCS_MAC_LENGTH) == 0) ) | ||
1206 | break; | ||
1207 | } | ||
1208 | if (im4 == NULL) | ||
1209 | ipm->ipm_state = LCS_IPM_STATE_DEL_REQUIRED; | ||
1210 | } | ||
1211 | spin_unlock_irqrestore(&card->ipm_lock, flags); | ||
1212 | } | ||
1213 | |||
1214 | static inline struct lcs_ipm_list * | ||
1215 | lcs_check_addr_entry(struct lcs_card *card, struct ip_mc_list *im4, char *buf) | ||
1216 | { | ||
1217 | struct lcs_ipm_list *tmp, *ipm = NULL; | ||
1218 | struct list_head *l; | ||
1219 | unsigned long flags; | ||
1220 | |||
1221 | LCS_DBF_TEXT(4, trace, "chkmcent"); | ||
1222 | spin_lock_irqsave(&card->ipm_lock, flags); | ||
1223 | list_for_each(l, &card->ipm_list) { | ||
1224 | tmp = list_entry(l, struct lcs_ipm_list, list); | ||
1225 | if ( (tmp->ipm.ip_addr == im4->multiaddr) && | ||
1226 | (memcmp(buf, &tmp->ipm.mac_addr, | ||
1227 | LCS_MAC_LENGTH) == 0) ) { | ||
1228 | ipm = tmp; | ||
1229 | break; | ||
1230 | } | ||
1231 | } | ||
1232 | spin_unlock_irqrestore(&card->ipm_lock, flags); | ||
1233 | return ipm; | ||
1234 | } | ||
1235 | |||
1236 | static inline void | ||
1237 | lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) | ||
1238 | { | ||
1239 | |||
1240 | struct ip_mc_list *im4; | ||
1241 | struct lcs_ipm_list *ipm; | ||
1242 | char buf[MAX_ADDR_LEN]; | ||
1243 | unsigned long flags; | ||
1244 | |||
1245 | LCS_DBF_TEXT(4, trace, "setmclst"); | ||
1246 | for (im4 = in4_dev->mc_list; im4; im4 = im4->next) { | ||
1247 | lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev); | ||
1248 | ipm = lcs_check_addr_entry(card, im4, buf); | ||
1249 | if (ipm != NULL) | ||
1250 | continue; /* Address already in list. */ | ||
1251 | ipm = (struct lcs_ipm_list *) | ||
1252 | kmalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC); | ||
1253 | if (ipm == NULL) { | ||
1254 | PRINT_INFO("Not enough memory to add " | ||
1255 | "new multicast entry!\n"); | ||
1256 | break; | ||
1257 | } | ||
1258 | memset(ipm, 0, sizeof(struct lcs_ipm_list)); | ||
1259 | memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); | ||
1260 | ipm->ipm.ip_addr = im4->multiaddr; | ||
1261 | ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED; | ||
1262 | spin_lock_irqsave(&card->ipm_lock, flags); | ||
1263 | list_add(&ipm->list, &card->ipm_list); | ||
1264 | spin_unlock_irqrestore(&card->ipm_lock, flags); | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1268 | static int | ||
1269 | lcs_register_mc_addresses(void *data) | ||
1270 | { | ||
1271 | struct lcs_card *card; | ||
1272 | struct in_device *in4_dev; | ||
1273 | |||
1274 | card = (struct lcs_card *) data; | ||
1275 | daemonize("regipm"); | ||
1276 | |||
1277 | if (!lcs_do_run_thread(card, LCS_SET_MC_THREAD)) | ||
1278 | return 0; | ||
1279 | LCS_DBF_TEXT(4, trace, "regmulti"); | ||
1280 | |||
1281 | in4_dev = in_dev_get(card->dev); | ||
1282 | if (in4_dev == NULL) | ||
1283 | goto out; | ||
1284 | read_lock(&in4_dev->mc_list_lock); | ||
1285 | lcs_remove_mc_addresses(card,in4_dev); | ||
1286 | lcs_set_mc_addresses(card, in4_dev); | ||
1287 | read_unlock(&in4_dev->mc_list_lock); | ||
1288 | in_dev_put(in4_dev); | ||
1289 | |||
1290 | lcs_fix_multicast_list(card); | ||
1291 | out: | ||
1292 | lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD); | ||
1293 | return 0; | ||
1294 | } | ||
1295 | /** | ||
1296 | * function called by net device to | ||
1297 | * handle multicast address relevant things | ||
1298 | */ | ||
1299 | static void | ||
1300 | lcs_set_multicast_list(struct net_device *dev) | ||
1301 | { | ||
1302 | struct lcs_card *card; | ||
1303 | |||
1304 | LCS_DBF_TEXT(4, trace, "setmulti"); | ||
1305 | card = (struct lcs_card *) dev->priv; | ||
1306 | |||
1307 | if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD)) { | ||
1308 | schedule_work(&card->kernel_thread_starter); | ||
1309 | } | ||
1310 | } | ||
1311 | |||
1312 | #endif /* CONFIG_IP_MULTICAST */ | ||
1313 | |||
1314 | static long | ||
1315 | lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb) | ||
1316 | { | ||
1317 | if (!IS_ERR(irb)) | ||
1318 | return 0; | ||
1319 | |||
1320 | switch (PTR_ERR(irb)) { | ||
1321 | case -EIO: | ||
1322 | PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id); | ||
1323 | LCS_DBF_TEXT(2, trace, "ckirberr"); | ||
1324 | LCS_DBF_TEXT_(2, trace, " rc%d", -EIO); | ||
1325 | break; | ||
1326 | case -ETIMEDOUT: | ||
1327 | PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id); | ||
1328 | LCS_DBF_TEXT(2, trace, "ckirberr"); | ||
1329 | LCS_DBF_TEXT_(2, trace, " rc%d", -ETIMEDOUT); | ||
1330 | break; | ||
1331 | default: | ||
1332 | PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), | ||
1333 | cdev->dev.bus_id); | ||
1334 | LCS_DBF_TEXT(2, trace, "ckirberr"); | ||
1335 | LCS_DBF_TEXT(2, trace, " rc???"); | ||
1336 | } | ||
1337 | return PTR_ERR(irb); | ||
1338 | } | ||
1339 | |||
1340 | |||
1341 | /** | ||
1342 | * IRQ Handler for LCS channels | ||
1343 | */ | ||
1344 | static void | ||
1345 | lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | ||
1346 | { | ||
1347 | struct lcs_card *card; | ||
1348 | struct lcs_channel *channel; | ||
1349 | int index; | ||
1350 | |||
1351 | if (lcs_check_irb_error(cdev, irb)) | ||
1352 | return; | ||
1353 | |||
1354 | card = CARD_FROM_DEV(cdev); | ||
1355 | if (card->read.ccwdev == cdev) | ||
1356 | channel = &card->read; | ||
1357 | else | ||
1358 | channel = &card->write; | ||
1359 | |||
1360 | LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id); | ||
1361 | LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat); | ||
1362 | LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl); | ||
1363 | |||
1364 | /* How far in the ccw chain have we processed? */ | ||
1365 | if ((channel->state != CH_STATE_INIT) && | ||
1366 | (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { | ||
1367 | index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) | ||
1368 | - channel->ccws; | ||
1369 | if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) || | ||
1370 | (irb->scsw.cstat | SCHN_STAT_PCI)) | ||
1371 | /* Bloody io subsystem tells us lies about cpa... */ | ||
1372 | index = (index - 1) & (LCS_NUM_BUFFS - 1); | ||
1373 | while (channel->io_idx != index) { | ||
1374 | __lcs_processed_buffer(channel, | ||
1375 | channel->iob + channel->io_idx); | ||
1376 | channel->io_idx = | ||
1377 | (channel->io_idx + 1) & (LCS_NUM_BUFFS - 1); | ||
1378 | } | ||
1379 | } | ||
1380 | |||
1381 | if ((irb->scsw.dstat & DEV_STAT_DEV_END) || | ||
1382 | (irb->scsw.dstat & DEV_STAT_CHN_END) || | ||
1383 | (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) | ||
1384 | /* Mark channel as stopped. */ | ||
1385 | channel->state = CH_STATE_STOPPED; | ||
1386 | else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) | ||
1387 | /* CCW execution stopped on a suspend bit. */ | ||
1388 | channel->state = CH_STATE_SUSPENDED; | ||
1389 | |||
1390 | if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { | ||
1391 | if (irb->scsw.cc != 0) { | ||
1392 | ccw_device_halt(channel->ccwdev, (addr_t) channel); | ||
1393 | return; | ||
1394 | } | ||
1395 | /* The channel has been stopped by halt_IO. */ | ||
1396 | channel->state = CH_STATE_HALTED; | ||
1397 | } | ||
1398 | |||
1399 | if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { | ||
1400 | channel->state = CH_STATE_CLEARED; | ||
1401 | } | ||
1402 | /* Do the rest in the tasklet. */ | ||
1403 | tasklet_schedule(&channel->irq_tasklet); | ||
1404 | } | ||
1405 | |||
1406 | /** | ||
1407 | * Tasklet for IRQ handler | ||
1408 | */ | ||
1409 | static void | ||
1410 | lcs_tasklet(unsigned long data) | ||
1411 | { | ||
1412 | unsigned long flags; | ||
1413 | struct lcs_channel *channel; | ||
1414 | struct lcs_buffer *iob; | ||
1415 | int buf_idx; | ||
1416 | int rc; | ||
1417 | |||
1418 | channel = (struct lcs_channel *) data; | ||
1419 | LCS_DBF_TEXT_(5, trace, "tlet%s",channel->ccwdev->dev.bus_id); | ||
1420 | |||
1421 | /* Check for processed buffers. */ | ||
1422 | iob = channel->iob; | ||
1423 | buf_idx = channel->buf_idx; | ||
1424 | while (iob[buf_idx].state == BUF_STATE_PROCESSED) { | ||
1425 | /* Do the callback thing. */ | ||
1426 | if (iob[buf_idx].callback != NULL) | ||
1427 | iob[buf_idx].callback(channel, iob + buf_idx); | ||
1428 | buf_idx = (buf_idx + 1) & (LCS_NUM_BUFFS - 1); | ||
1429 | } | ||
1430 | channel->buf_idx = buf_idx; | ||
1431 | |||
1432 | if (channel->state == CH_STATE_STOPPED) | ||
1433 | // FIXME: what if rc != 0 ?? | ||
1434 | rc = lcs_start_channel(channel); | ||
1435 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | ||
1436 | if (channel->state == CH_STATE_SUSPENDED && | ||
1437 | channel->iob[channel->io_idx].state == BUF_STATE_READY) { | ||
1438 | // FIXME: what if rc != 0 ?? | ||
1439 | rc = __lcs_resume_channel(channel); | ||
1440 | } | ||
1441 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | ||
1442 | |||
1443 | /* Something happened on the channel. Wake up waiters. */ | ||
1444 | wake_up(&channel->wait_q); | ||
1445 | } | ||
1446 | |||
1447 | /** | ||
1448 | * Finish current tx buffer and make it ready for transmit. | ||
1449 | */ | ||
1450 | static void | ||
1451 | __lcs_emit_txbuffer(struct lcs_card *card) | ||
1452 | { | ||
1453 | LCS_DBF_TEXT(5, trace, "emittx"); | ||
1454 | *(__u16 *)(card->tx_buffer->data + card->tx_buffer->count) = 0; | ||
1455 | card->tx_buffer->count += 2; | ||
1456 | lcs_ready_buffer(&card->write, card->tx_buffer); | ||
1457 | card->tx_buffer = NULL; | ||
1458 | card->tx_emitted++; | ||
1459 | } | ||
1460 | |||
1461 | /** | ||
1462 | * Callback for finished tx buffers. | ||
1463 | */ | ||
1464 | static void | ||
1465 | lcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer) | ||
1466 | { | ||
1467 | struct lcs_card *card; | ||
1468 | |||
1469 | LCS_DBF_TEXT(5, trace, "txbuffcb"); | ||
1470 | /* Put buffer back to pool. */ | ||
1471 | lcs_release_buffer(channel, buffer); | ||
1472 | card = (struct lcs_card *) | ||
1473 | ((char *) channel - offsetof(struct lcs_card, write)); | ||
1474 | spin_lock(&card->lock); | ||
1475 | card->tx_emitted--; | ||
1476 | if (card->tx_emitted <= 0 && card->tx_buffer != NULL) | ||
1477 | /* | ||
1478 | * Last running tx buffer has finished. Submit partially | ||
1479 | * filled current buffer. | ||
1480 | */ | ||
1481 | __lcs_emit_txbuffer(card); | ||
1482 | spin_unlock(&card->lock); | ||
1483 | } | ||
1484 | |||
1485 | /** | ||
1486 | * Packet transmit function called by network stack | ||
1487 | */ | ||
1488 | static int | ||
1489 | __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, | ||
1490 | struct net_device *dev) | ||
1491 | { | ||
1492 | struct lcs_header *header; | ||
1493 | |||
1494 | LCS_DBF_TEXT(5, trace, "hardxmit"); | ||
1495 | if (skb == NULL) { | ||
1496 | card->stats.tx_dropped++; | ||
1497 | card->stats.tx_errors++; | ||
1498 | return -EIO; | ||
1499 | } | ||
1500 | if (card->state != DEV_STATE_UP) { | ||
1501 | dev_kfree_skb(skb); | ||
1502 | card->stats.tx_dropped++; | ||
1503 | card->stats.tx_errors++; | ||
1504 | card->stats.tx_carrier_errors++; | ||
1505 | return 0; | ||
1506 | } | ||
1507 | if (netif_queue_stopped(dev) ) { | ||
1508 | card->stats.tx_dropped++; | ||
1509 | return -EBUSY; | ||
1510 | } | ||
1511 | if (card->tx_buffer != NULL && | ||
1512 | card->tx_buffer->count + sizeof(struct lcs_header) + | ||
1513 | skb->len + sizeof(u16) > LCS_IOBUFFERSIZE) | ||
1514 | /* skb too big for current tx buffer. */ | ||
1515 | __lcs_emit_txbuffer(card); | ||
1516 | if (card->tx_buffer == NULL) { | ||
1517 | /* Get new tx buffer */ | ||
1518 | card->tx_buffer = lcs_get_buffer(&card->write); | ||
1519 | if (card->tx_buffer == NULL) { | ||
1520 | card->stats.tx_dropped++; | ||
1521 | return -EBUSY; | ||
1522 | } | ||
1523 | card->tx_buffer->callback = lcs_txbuffer_cb; | ||
1524 | card->tx_buffer->count = 0; | ||
1525 | } | ||
1526 | header = (struct lcs_header *) | ||
1527 | (card->tx_buffer->data + card->tx_buffer->count); | ||
1528 | card->tx_buffer->count += skb->len + sizeof(struct lcs_header); | ||
1529 | header->offset = card->tx_buffer->count; | ||
1530 | header->type = card->lan_type; | ||
1531 | header->slot = card->portno; | ||
1532 | memcpy(header + 1, skb->data, skb->len); | ||
1533 | card->stats.tx_bytes += skb->len; | ||
1534 | card->stats.tx_packets++; | ||
1535 | dev_kfree_skb(skb); | ||
1536 | if (card->tx_emitted <= 0) | ||
1537 | /* If this is the first tx buffer emit it immediately. */ | ||
1538 | __lcs_emit_txbuffer(card); | ||
1539 | return 0; | ||
1540 | } | ||
1541 | |||
1542 | static int | ||
1543 | lcs_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
1544 | { | ||
1545 | struct lcs_card *card; | ||
1546 | int rc; | ||
1547 | |||
1548 | LCS_DBF_TEXT(5, trace, "pktxmit"); | ||
1549 | card = (struct lcs_card *) dev->priv; | ||
1550 | spin_lock(&card->lock); | ||
1551 | rc = __lcs_start_xmit(card, skb, dev); | ||
1552 | spin_unlock(&card->lock); | ||
1553 | return rc; | ||
1554 | } | ||
1555 | |||
1556 | /** | ||
1557 | * send startlan and lanstat command to make LCS device ready | ||
1558 | */ | ||
1559 | static int | ||
1560 | lcs_startlan_auto(struct lcs_card *card) | ||
1561 | { | ||
1562 | int rc; | ||
1563 | |||
1564 | LCS_DBF_TEXT(2, trace, "strtauto"); | ||
1565 | #ifdef CONFIG_NET_ETHERNET | ||
1566 | card->lan_type = LCS_FRAME_TYPE_ENET; | ||
1567 | rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); | ||
1568 | if (rc == 0) | ||
1569 | return 0; | ||
1570 | |||
1571 | #endif | ||
1572 | #ifdef CONFIG_TR | ||
1573 | card->lan_type = LCS_FRAME_TYPE_TR; | ||
1574 | rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); | ||
1575 | if (rc == 0) | ||
1576 | return 0; | ||
1577 | #endif | ||
1578 | #ifdef CONFIG_FDDI | ||
1579 | card->lan_type = LCS_FRAME_TYPE_FDDI; | ||
1580 | rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); | ||
1581 | if (rc == 0) | ||
1582 | return 0; | ||
1583 | #endif | ||
1584 | return -EIO; | ||
1585 | } | ||
1586 | |||
1587 | static int | ||
1588 | lcs_startlan(struct lcs_card *card) | ||
1589 | { | ||
1590 | int rc, i; | ||
1591 | |||
1592 | LCS_DBF_TEXT(2, trace, "startlan"); | ||
1593 | rc = 0; | ||
1594 | if (card->portno != LCS_INVALID_PORT_NO) { | ||
1595 | if (card->lan_type == LCS_FRAME_TYPE_AUTO) | ||
1596 | rc = lcs_startlan_auto(card); | ||
1597 | else | ||
1598 | rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); | ||
1599 | } else { | ||
1600 | for (i = 0; i <= 16; i++) { | ||
1601 | card->portno = i; | ||
1602 | if (card->lan_type != LCS_FRAME_TYPE_AUTO) | ||
1603 | rc = lcs_send_startlan(card, | ||
1604 | LCS_INITIATOR_TCPIP); | ||
1605 | else | ||
1606 | /* autodetecting lan type */ | ||
1607 | rc = lcs_startlan_auto(card); | ||
1608 | if (rc == 0) | ||
1609 | break; | ||
1610 | } | ||
1611 | } | ||
1612 | if (rc == 0) | ||
1613 | return lcs_send_lanstat(card); | ||
1614 | return rc; | ||
1615 | } | ||
1616 | |||
1617 | /** | ||
1618 | * LCS detect function | ||
1619 | * setup channels and make them I/O ready | ||
1620 | */ | ||
1621 | static int | ||
1622 | lcs_detect(struct lcs_card *card) | ||
1623 | { | ||
1624 | int rc = 0; | ||
1625 | |||
1626 | LCS_DBF_TEXT(2, setup, "lcsdetct"); | ||
1627 | /* start/reset card */ | ||
1628 | if (card->dev) | ||
1629 | netif_stop_queue(card->dev); | ||
1630 | rc = lcs_stop_channels(card); | ||
1631 | if (rc == 0) { | ||
1632 | rc = lcs_start_channels(card); | ||
1633 | if (rc == 0) { | ||
1634 | rc = lcs_send_startup(card, LCS_INITIATOR_TCPIP); | ||
1635 | if (rc == 0) | ||
1636 | rc = lcs_startlan(card); | ||
1637 | } | ||
1638 | } | ||
1639 | if (rc == 0) { | ||
1640 | card->state = DEV_STATE_UP; | ||
1641 | } else { | ||
1642 | card->state = DEV_STATE_DOWN; | ||
1643 | card->write.state = CH_STATE_INIT; | ||
1644 | card->read.state = CH_STATE_INIT; | ||
1645 | } | ||
1646 | return rc; | ||
1647 | } | ||
1648 | |||
1649 | /** | ||
1650 | * reset card | ||
1651 | */ | ||
1652 | static int | ||
1653 | lcs_resetcard(struct lcs_card *card) | ||
1654 | { | ||
1655 | int retries; | ||
1656 | |||
1657 | LCS_DBF_TEXT(2, trace, "rescard"); | ||
1658 | for (retries = 0; retries < 10; retries++) { | ||
1659 | if (lcs_detect(card) == 0) { | ||
1660 | netif_wake_queue(card->dev); | ||
1661 | card->state = DEV_STATE_UP; | ||
1662 | PRINT_INFO("LCS device %s successfully restarted!\n", | ||
1663 | card->dev->name); | ||
1664 | return 0; | ||
1665 | } | ||
1666 | msleep(3000); | ||
1667 | } | ||
1668 | PRINT_ERR("Error in Reseting LCS card!\n"); | ||
1669 | return -EIO; | ||
1670 | } | ||
1671 | |||
1672 | |||
1673 | /** | ||
1674 | * LCS Stop card | ||
1675 | */ | ||
1676 | static int | ||
1677 | lcs_stopcard(struct lcs_card *card) | ||
1678 | { | ||
1679 | int rc; | ||
1680 | |||
1681 | LCS_DBF_TEXT(3, setup, "stopcard"); | ||
1682 | |||
1683 | if (card->read.state != CH_STATE_STOPPED && | ||
1684 | card->write.state != CH_STATE_STOPPED && | ||
1685 | card->state == DEV_STATE_UP) { | ||
1686 | lcs_clear_multicast_list(card); | ||
1687 | rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); | ||
1688 | rc = lcs_send_shutdown(card); | ||
1689 | } | ||
1690 | rc = lcs_stop_channels(card); | ||
1691 | card->state = DEV_STATE_DOWN; | ||
1692 | |||
1693 | return rc; | ||
1694 | } | ||
1695 | |||
1696 | /** | ||
1697 | * LGW initiated commands | ||
1698 | */ | ||
1699 | static int | ||
1700 | lcs_lgw_startlan_thread(void *data) | ||
1701 | { | ||
1702 | struct lcs_card *card; | ||
1703 | |||
1704 | card = (struct lcs_card *) data; | ||
1705 | daemonize("lgwstpln"); | ||
1706 | |||
1707 | if (!lcs_do_run_thread(card, LCS_STARTLAN_THREAD)) | ||
1708 | return 0; | ||
1709 | LCS_DBF_TEXT(4, trace, "lgwstpln"); | ||
1710 | if (card->dev) | ||
1711 | netif_stop_queue(card->dev); | ||
1712 | if (lcs_startlan(card) == 0) { | ||
1713 | netif_wake_queue(card->dev); | ||
1714 | card->state = DEV_STATE_UP; | ||
1715 | PRINT_INFO("LCS Startlan for device %s succeeded!\n", | ||
1716 | card->dev->name); | ||
1717 | |||
1718 | } else | ||
1719 | PRINT_ERR("LCS Startlan for device %s failed!\n", | ||
1720 | card->dev->name); | ||
1721 | lcs_clear_thread_running_bit(card, LCS_STARTLAN_THREAD); | ||
1722 | return 0; | ||
1723 | } | ||
1724 | |||
1725 | /** | ||
1726 | * Send startup command initiated by Lan Gateway | ||
1727 | */ | ||
1728 | static int | ||
1729 | lcs_lgw_startup_thread(void *data) | ||
1730 | { | ||
1731 | int rc; | ||
1732 | |||
1733 | struct lcs_card *card; | ||
1734 | |||
1735 | card = (struct lcs_card *) data; | ||
1736 | daemonize("lgwstaln"); | ||
1737 | |||
1738 | if (!lcs_do_run_thread(card, LCS_STARTUP_THREAD)) | ||
1739 | return 0; | ||
1740 | LCS_DBF_TEXT(4, trace, "lgwstaln"); | ||
1741 | if (card->dev) | ||
1742 | netif_stop_queue(card->dev); | ||
1743 | rc = lcs_send_startup(card, LCS_INITIATOR_LGW); | ||
1744 | if (rc != 0) { | ||
1745 | PRINT_ERR("Startup for LCS device %s initiated " \ | ||
1746 | "by LGW failed!\nReseting card ...\n", | ||
1747 | card->dev->name); | ||
1748 | /* do a card reset */ | ||
1749 | rc = lcs_resetcard(card); | ||
1750 | if (rc == 0) | ||
1751 | goto Done; | ||
1752 | } | ||
1753 | rc = lcs_startlan(card); | ||
1754 | if (rc == 0) { | ||
1755 | netif_wake_queue(card->dev); | ||
1756 | card->state = DEV_STATE_UP; | ||
1757 | } | ||
1758 | Done: | ||
1759 | if (rc == 0) | ||
1760 | PRINT_INFO("LCS Startup for device %s succeeded!\n", | ||
1761 | card->dev->name); | ||
1762 | else | ||
1763 | PRINT_ERR("LCS Startup for device %s failed!\n", | ||
1764 | card->dev->name); | ||
1765 | lcs_clear_thread_running_bit(card, LCS_STARTUP_THREAD); | ||
1766 | return 0; | ||
1767 | } | ||
1768 | |||
1769 | |||
1770 | /** | ||
1771 | * send stoplan command initiated by Lan Gateway | ||
1772 | */ | ||
1773 | static int | ||
1774 | lcs_lgw_stoplan_thread(void *data) | ||
1775 | { | ||
1776 | struct lcs_card *card; | ||
1777 | int rc; | ||
1778 | |||
1779 | card = (struct lcs_card *) data; | ||
1780 | daemonize("lgwstop"); | ||
1781 | |||
1782 | if (!lcs_do_run_thread(card, LCS_STOPLAN_THREAD)) | ||
1783 | return 0; | ||
1784 | LCS_DBF_TEXT(4, trace, "lgwstop"); | ||
1785 | if (card->dev) | ||
1786 | netif_stop_queue(card->dev); | ||
1787 | if (lcs_send_stoplan(card, LCS_INITIATOR_LGW) == 0) | ||
1788 | PRINT_INFO("Stoplan for %s initiated by LGW succeeded!\n", | ||
1789 | card->dev->name); | ||
1790 | else | ||
1791 | PRINT_ERR("Stoplan %s initiated by LGW failed!\n", | ||
1792 | card->dev->name); | ||
1793 | /*Try to reset the card, stop it on failure */ | ||
1794 | rc = lcs_resetcard(card); | ||
1795 | if (rc != 0) | ||
1796 | rc = lcs_stopcard(card); | ||
1797 | lcs_clear_thread_running_bit(card, LCS_STOPLAN_THREAD); | ||
1798 | return rc; | ||
1799 | } | ||
1800 | |||
1801 | /** | ||
1802 | * Kernel Thread helper functions for LGW initiated commands | ||
1803 | */ | ||
1804 | static void | ||
1805 | lcs_start_kernel_thread(struct lcs_card *card) | ||
1806 | { | ||
1807 | LCS_DBF_TEXT(5, trace, "krnthrd"); | ||
1808 | if (lcs_do_start_thread(card, LCS_STARTUP_THREAD)) | ||
1809 | kernel_thread(lcs_lgw_startup_thread, (void *) card, SIGCHLD); | ||
1810 | if (lcs_do_start_thread(card, LCS_STARTLAN_THREAD)) | ||
1811 | kernel_thread(lcs_lgw_startlan_thread, (void *) card, SIGCHLD); | ||
1812 | if (lcs_do_start_thread(card, LCS_STOPLAN_THREAD)) | ||
1813 | kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD); | ||
1814 | #ifdef CONFIG_IP_MULTICAST | ||
1815 | if (lcs_do_start_thread(card, LCS_SET_MC_THREAD)) | ||
1816 | kernel_thread(lcs_register_mc_addresses, (void *) card, SIGCHLD); | ||
1817 | #endif | ||
1818 | } | ||
1819 | |||
1820 | /** | ||
1821 | * Process control frames. | ||
1822 | */ | ||
1823 | static void | ||
1824 | lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) | ||
1825 | { | ||
1826 | LCS_DBF_TEXT(5, trace, "getctrl"); | ||
1827 | if (cmd->initiator == LCS_INITIATOR_LGW) { | ||
1828 | switch(cmd->cmd_code) { | ||
1829 | case LCS_CMD_STARTUP: | ||
1830 | if (!lcs_set_thread_start_bit(card, | ||
1831 | LCS_STARTUP_THREAD)) | ||
1832 | schedule_work(&card->kernel_thread_starter); | ||
1833 | break; | ||
1834 | case LCS_CMD_STARTLAN: | ||
1835 | if (!lcs_set_thread_start_bit(card, | ||
1836 | LCS_STARTLAN_THREAD)) | ||
1837 | schedule_work(&card->kernel_thread_starter); | ||
1838 | break; | ||
1839 | case LCS_CMD_STOPLAN: | ||
1840 | if (!lcs_set_thread_start_bit(card, | ||
1841 | LCS_STOPLAN_THREAD)) | ||
1842 | schedule_work(&card->kernel_thread_starter); | ||
1843 | break; | ||
1844 | default: | ||
1845 | PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); | ||
1846 | break; | ||
1847 | } | ||
1848 | } else | ||
1849 | lcs_notify_lancmd_waiters(card, cmd); | ||
1850 | } | ||
1851 | |||
1852 | /** | ||
1853 | * Unpack network packet. | ||
1854 | */ | ||
1855 | static void | ||
1856 | lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len) | ||
1857 | { | ||
1858 | struct sk_buff *skb; | ||
1859 | |||
1860 | LCS_DBF_TEXT(5, trace, "getskb"); | ||
1861 | if (card->dev == NULL || | ||
1862 | card->state != DEV_STATE_UP) | ||
1863 | /* The card isn't up. Ignore the packet. */ | ||
1864 | return; | ||
1865 | |||
1866 | skb = dev_alloc_skb(skb_len); | ||
1867 | if (skb == NULL) { | ||
1868 | PRINT_ERR("LCS: alloc_skb failed for device=%s\n", | ||
1869 | card->dev->name); | ||
1870 | card->stats.rx_dropped++; | ||
1871 | return; | ||
1872 | } | ||
1873 | skb->dev = card->dev; | ||
1874 | memcpy(skb_put(skb, skb_len), skb_data, skb_len); | ||
1875 | skb->protocol = card->lan_type_trans(skb, card->dev); | ||
1876 | card->stats.rx_bytes += skb_len; | ||
1877 | card->stats.rx_packets++; | ||
1878 | *((__u32 *)skb->cb) = ++card->pkt_seq; | ||
1879 | netif_rx(skb); | ||
1880 | } | ||
1881 | |||
1882 | /** | ||
1883 | * LCS main routine to get packets and lancmd replies from the buffers | ||
1884 | */ | ||
1885 | static void | ||
1886 | lcs_get_frames_cb(struct lcs_channel *channel, struct lcs_buffer *buffer) | ||
1887 | { | ||
1888 | struct lcs_card *card; | ||
1889 | struct lcs_header *lcs_hdr; | ||
1890 | __u16 offset; | ||
1891 | |||
1892 | LCS_DBF_TEXT(5, trace, "lcsgtpkt"); | ||
1893 | lcs_hdr = (struct lcs_header *) buffer->data; | ||
1894 | if (lcs_hdr->offset == LCS_ILLEGAL_OFFSET) { | ||
1895 | LCS_DBF_TEXT(4, trace, "-eiogpkt"); | ||
1896 | return; | ||
1897 | } | ||
1898 | card = (struct lcs_card *) | ||
1899 | ((char *) channel - offsetof(struct lcs_card, read)); | ||
1900 | offset = 0; | ||
1901 | while (lcs_hdr->offset != 0) { | ||
1902 | if (lcs_hdr->offset <= 0 || | ||
1903 | lcs_hdr->offset > LCS_IOBUFFERSIZE || | ||
1904 | lcs_hdr->offset < offset) { | ||
1905 | /* Offset invalid. */ | ||
1906 | card->stats.rx_length_errors++; | ||
1907 | card->stats.rx_errors++; | ||
1908 | return; | ||
1909 | } | ||
1910 | /* What kind of frame is it? */ | ||
1911 | if (lcs_hdr->type == LCS_FRAME_TYPE_CONTROL) | ||
1912 | /* Control frame. */ | ||
1913 | lcs_get_control(card, (struct lcs_cmd *) lcs_hdr); | ||
1914 | else if (lcs_hdr->type == LCS_FRAME_TYPE_ENET || | ||
1915 | lcs_hdr->type == LCS_FRAME_TYPE_TR || | ||
1916 | lcs_hdr->type == LCS_FRAME_TYPE_FDDI) | ||
1917 | /* Normal network packet. */ | ||
1918 | lcs_get_skb(card, (char *)(lcs_hdr + 1), | ||
1919 | lcs_hdr->offset - offset - | ||
1920 | sizeof(struct lcs_header)); | ||
1921 | else | ||
1922 | /* Unknown frame type. */ | ||
1923 | ; // FIXME: error message ? | ||
1924 | /* Proceed to next frame. */ | ||
1925 | offset = lcs_hdr->offset; | ||
1926 | lcs_hdr->offset = LCS_ILLEGAL_OFFSET; | ||
1927 | lcs_hdr = (struct lcs_header *) (buffer->data + offset); | ||
1928 | } | ||
1929 | /* The buffer is now empty. Make it ready again. */ | ||
1930 | lcs_ready_buffer(&card->read, buffer); | ||
1931 | } | ||
1932 | |||
1933 | /** | ||
1934 | * get network statistics for ifconfig and other user programs | ||
1935 | */ | ||
1936 | static struct net_device_stats * | ||
1937 | lcs_getstats(struct net_device *dev) | ||
1938 | { | ||
1939 | struct lcs_card *card; | ||
1940 | |||
1941 | LCS_DBF_TEXT(4, trace, "netstats"); | ||
1942 | card = (struct lcs_card *) dev->priv; | ||
1943 | return &card->stats; | ||
1944 | } | ||
1945 | |||
1946 | /** | ||
1947 | * stop lcs device | ||
1948 | * This function will be called by user doing ifconfig xxx down | ||
1949 | */ | ||
1950 | static int | ||
1951 | lcs_stop_device(struct net_device *dev) | ||
1952 | { | ||
1953 | struct lcs_card *card; | ||
1954 | int rc; | ||
1955 | |||
1956 | LCS_DBF_TEXT(2, trace, "stopdev"); | ||
1957 | card = (struct lcs_card *) dev->priv; | ||
1958 | netif_stop_queue(dev); | ||
1959 | dev->flags &= ~IFF_UP; | ||
1960 | rc = lcs_stopcard(card); | ||
1961 | if (rc) | ||
1962 | PRINT_ERR("Try it again!\n "); | ||
1963 | return rc; | ||
1964 | } | ||
1965 | |||
1966 | /** | ||
1967 | * start lcs device and make it runnable | ||
1968 | * This function will be called by user doing ifconfig xxx up | ||
1969 | */ | ||
1970 | static int | ||
1971 | lcs_open_device(struct net_device *dev) | ||
1972 | { | ||
1973 | struct lcs_card *card; | ||
1974 | int rc; | ||
1975 | |||
1976 | LCS_DBF_TEXT(2, trace, "opendev"); | ||
1977 | card = (struct lcs_card *) dev->priv; | ||
1978 | /* initialize statistics */ | ||
1979 | rc = lcs_detect(card); | ||
1980 | if (rc) { | ||
1981 | PRINT_ERR("LCS:Error in opening device!\n"); | ||
1982 | |||
1983 | } else { | ||
1984 | dev->flags |= IFF_UP; | ||
1985 | netif_wake_queue(dev); | ||
1986 | card->state = DEV_STATE_UP; | ||
1987 | } | ||
1988 | return rc; | ||
1989 | } | ||
1990 | |||
1991 | /** | ||
1992 | * show function for portno called by cat or similar things | ||
1993 | */ | ||
1994 | static ssize_t | ||
1995 | lcs_portno_show (struct device *dev, char *buf) | ||
1996 | { | ||
1997 | struct lcs_card *card; | ||
1998 | |||
1999 | card = (struct lcs_card *)dev->driver_data; | ||
2000 | |||
2001 | if (!card) | ||
2002 | return 0; | ||
2003 | |||
2004 | return sprintf(buf, "%d\n", card->portno); | ||
2005 | } | ||
2006 | |||
2007 | /** | ||
2008 | * store the value which is piped to file portno | ||
2009 | */ | ||
2010 | static ssize_t | ||
2011 | lcs_portno_store (struct device *dev, const char *buf, size_t count) | ||
2012 | { | ||
2013 | struct lcs_card *card; | ||
2014 | int value; | ||
2015 | |||
2016 | card = (struct lcs_card *)dev->driver_data; | ||
2017 | |||
2018 | if (!card) | ||
2019 | return 0; | ||
2020 | |||
2021 | sscanf(buf, "%u", &value); | ||
2022 | /* TODO: sanity checks */ | ||
2023 | card->portno = value; | ||
2024 | |||
2025 | return count; | ||
2026 | |||
2027 | } | ||
2028 | |||
2029 | static DEVICE_ATTR(portno, 0644, lcs_portno_show, lcs_portno_store); | ||
2030 | |||
2031 | static ssize_t | ||
2032 | lcs_type_show(struct device *dev, char *buf) | ||
2033 | { | ||
2034 | struct ccwgroup_device *cgdev; | ||
2035 | |||
2036 | cgdev = to_ccwgroupdev(dev); | ||
2037 | if (!cgdev) | ||
2038 | return -ENODEV; | ||
2039 | |||
2040 | return sprintf(buf, "%s\n", cu3088_type[cgdev->cdev[0]->id.driver_info]); | ||
2041 | } | ||
2042 | |||
2043 | static DEVICE_ATTR(type, 0444, lcs_type_show, NULL); | ||
2044 | |||
2045 | static ssize_t | ||
2046 | lcs_timeout_show(struct device *dev, char *buf) | ||
2047 | { | ||
2048 | struct lcs_card *card; | ||
2049 | |||
2050 | card = (struct lcs_card *)dev->driver_data; | ||
2051 | |||
2052 | return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0; | ||
2053 | } | ||
2054 | |||
2055 | static ssize_t | ||
2056 | lcs_timeout_store (struct device *dev, const char *buf, size_t count) | ||
2057 | { | ||
2058 | struct lcs_card *card; | ||
2059 | int value; | ||
2060 | |||
2061 | card = (struct lcs_card *)dev->driver_data; | ||
2062 | |||
2063 | if (!card) | ||
2064 | return 0; | ||
2065 | |||
2066 | sscanf(buf, "%u", &value); | ||
2067 | /* TODO: sanity checks */ | ||
2068 | card->lancmd_timeout = value; | ||
2069 | |||
2070 | return count; | ||
2071 | |||
2072 | } | ||
2073 | |||
2074 | DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); | ||
2075 | |||
2076 | static struct attribute * lcs_attrs[] = { | ||
2077 | &dev_attr_portno.attr, | ||
2078 | &dev_attr_type.attr, | ||
2079 | &dev_attr_lancmd_timeout.attr, | ||
2080 | NULL, | ||
2081 | }; | ||
2082 | |||
2083 | static struct attribute_group lcs_attr_group = { | ||
2084 | .attrs = lcs_attrs, | ||
2085 | }; | ||
2086 | |||
2087 | /** | ||
2088 | * lcs_probe_device is called on establishing a new ccwgroup_device. | ||
2089 | */ | ||
2090 | static int | ||
2091 | lcs_probe_device(struct ccwgroup_device *ccwgdev) | ||
2092 | { | ||
2093 | struct lcs_card *card; | ||
2094 | int ret; | ||
2095 | |||
2096 | if (!get_device(&ccwgdev->dev)) | ||
2097 | return -ENODEV; | ||
2098 | |||
2099 | LCS_DBF_TEXT(2, setup, "add_dev"); | ||
2100 | card = lcs_alloc_card(); | ||
2101 | if (!card) { | ||
2102 | PRINT_ERR("Allocation of lcs card failed\n"); | ||
2103 | put_device(&ccwgdev->dev); | ||
2104 | return -ENOMEM; | ||
2105 | } | ||
2106 | ret = sysfs_create_group(&ccwgdev->dev.kobj, &lcs_attr_group); | ||
2107 | if (ret) { | ||
2108 | PRINT_ERR("Creating attributes failed"); | ||
2109 | lcs_free_card(card); | ||
2110 | put_device(&ccwgdev->dev); | ||
2111 | return ret; | ||
2112 | } | ||
2113 | ccwgdev->dev.driver_data = card; | ||
2114 | ccwgdev->cdev[0]->handler = lcs_irq; | ||
2115 | ccwgdev->cdev[1]->handler = lcs_irq; | ||
2116 | return 0; | ||
2117 | } | ||
2118 | |||
2119 | static int | ||
2120 | lcs_register_netdev(struct ccwgroup_device *ccwgdev) | ||
2121 | { | ||
2122 | struct lcs_card *card; | ||
2123 | |||
2124 | LCS_DBF_TEXT(2, setup, "regnetdv"); | ||
2125 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | ||
2126 | if (card->dev->reg_state != NETREG_UNINITIALIZED) | ||
2127 | return 0; | ||
2128 | SET_NETDEV_DEV(card->dev, &ccwgdev->dev); | ||
2129 | return register_netdev(card->dev); | ||
2130 | } | ||
2131 | |||
2132 | /** | ||
2133 | * lcs_new_device will be called by setting the group device online. | ||
2134 | */ | ||
2135 | |||
2136 | static int | ||
2137 | lcs_new_device(struct ccwgroup_device *ccwgdev) | ||
2138 | { | ||
2139 | struct lcs_card *card; | ||
2140 | struct net_device *dev=NULL; | ||
2141 | enum lcs_dev_states recover_state; | ||
2142 | int rc; | ||
2143 | |||
2144 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | ||
2145 | if (!card) | ||
2146 | return -ENODEV; | ||
2147 | |||
2148 | LCS_DBF_TEXT(2, setup, "newdev"); | ||
2149 | LCS_DBF_HEX(3, setup, &card, sizeof(void*)); | ||
2150 | card->read.ccwdev = ccwgdev->cdev[0]; | ||
2151 | card->write.ccwdev = ccwgdev->cdev[1]; | ||
2152 | |||
2153 | recover_state = card->state; | ||
2154 | ccw_device_set_online(card->read.ccwdev); | ||
2155 | ccw_device_set_online(card->write.ccwdev); | ||
2156 | |||
2157 | LCS_DBF_TEXT(3, setup, "lcsnewdv"); | ||
2158 | |||
2159 | lcs_setup_card(card); | ||
2160 | rc = lcs_detect(card); | ||
2161 | if (rc) { | ||
2162 | LCS_DBF_TEXT(2, setup, "dtctfail"); | ||
2163 | PRINT_WARN("Detection of LCS card failed with return code " | ||
2164 | "%d (0x%x)\n", rc, rc); | ||
2165 | lcs_stopcard(card); | ||
2166 | goto out; | ||
2167 | } | ||
2168 | if (card->dev) { | ||
2169 | LCS_DBF_TEXT(2, setup, "samedev"); | ||
2170 | LCS_DBF_HEX(3, setup, &card, sizeof(void*)); | ||
2171 | goto netdev_out; | ||
2172 | } | ||
2173 | switch (card->lan_type) { | ||
2174 | #ifdef CONFIG_NET_ETHERNET | ||
2175 | case LCS_FRAME_TYPE_ENET: | ||
2176 | card->lan_type_trans = eth_type_trans; | ||
2177 | dev = alloc_etherdev(0); | ||
2178 | break; | ||
2179 | #endif | ||
2180 | #ifdef CONFIG_TR | ||
2181 | case LCS_FRAME_TYPE_TR: | ||
2182 | card->lan_type_trans = tr_type_trans; | ||
2183 | dev = alloc_trdev(0); | ||
2184 | break; | ||
2185 | #endif | ||
2186 | #ifdef CONFIG_FDDI | ||
2187 | case LCS_FRAME_TYPE_FDDI: | ||
2188 | card->lan_type_trans = fddi_type_trans; | ||
2189 | dev = alloc_fddidev(0); | ||
2190 | break; | ||
2191 | #endif | ||
2192 | default: | ||
2193 | LCS_DBF_TEXT(3, setup, "errinit"); | ||
2194 | PRINT_ERR("LCS: Initialization failed\n"); | ||
2195 | PRINT_ERR("LCS: No device found!\n"); | ||
2196 | goto out; | ||
2197 | } | ||
2198 | if (!dev) | ||
2199 | goto out; | ||
2200 | card->dev = dev; | ||
2201 | netdev_out: | ||
2202 | card->dev->priv = card; | ||
2203 | card->dev->open = lcs_open_device; | ||
2204 | card->dev->stop = lcs_stop_device; | ||
2205 | card->dev->hard_start_xmit = lcs_start_xmit; | ||
2206 | card->dev->get_stats = lcs_getstats; | ||
2207 | SET_MODULE_OWNER(dev); | ||
2208 | if (lcs_register_netdev(ccwgdev) != 0) | ||
2209 | goto out; | ||
2210 | memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH); | ||
2211 | #ifdef CONFIG_IP_MULTICAST | ||
2212 | if (!lcs_check_multicast_support(card)) | ||
2213 | card->dev->set_multicast_list = lcs_set_multicast_list; | ||
2214 | #endif | ||
2215 | netif_stop_queue(card->dev); | ||
2216 | lcs_set_allowed_threads(card,0xffffffff); | ||
2217 | if (recover_state == DEV_STATE_RECOVER) { | ||
2218 | lcs_set_multicast_list(card->dev); | ||
2219 | card->dev->flags |= IFF_UP; | ||
2220 | netif_wake_queue(card->dev); | ||
2221 | card->state = DEV_STATE_UP; | ||
2222 | } else | ||
2223 | lcs_stopcard(card); | ||
2224 | |||
2225 | return 0; | ||
2226 | out: | ||
2227 | |||
2228 | ccw_device_set_offline(card->read.ccwdev); | ||
2229 | ccw_device_set_offline(card->write.ccwdev); | ||
2230 | return -ENODEV; | ||
2231 | } | ||
2232 | |||
2233 | /** | ||
2234 | * lcs_shutdown_device, called when setting the group device offline. | ||
2235 | */ | ||
2236 | static int | ||
2237 | lcs_shutdown_device(struct ccwgroup_device *ccwgdev) | ||
2238 | { | ||
2239 | struct lcs_card *card; | ||
2240 | enum lcs_dev_states recover_state; | ||
2241 | int ret; | ||
2242 | |||
2243 | LCS_DBF_TEXT(3, setup, "shtdndev"); | ||
2244 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | ||
2245 | if (!card) | ||
2246 | return -ENODEV; | ||
2247 | lcs_set_allowed_threads(card, 0); | ||
2248 | if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD)) | ||
2249 | return -ERESTARTSYS; | ||
2250 | LCS_DBF_HEX(3, setup, &card, sizeof(void*)); | ||
2251 | recover_state = card->state; | ||
2252 | |||
2253 | ret = lcs_stop_device(card->dev); | ||
2254 | ret = ccw_device_set_offline(card->read.ccwdev); | ||
2255 | ret = ccw_device_set_offline(card->write.ccwdev); | ||
2256 | if (recover_state == DEV_STATE_UP) { | ||
2257 | card->state = DEV_STATE_RECOVER; | ||
2258 | } | ||
2259 | if (ret) | ||
2260 | return ret; | ||
2261 | return 0; | ||
2262 | } | ||
2263 | |||
2264 | /** | ||
2265 | * lcs_remove_device, free buffers and card | ||
2266 | */ | ||
2267 | static void | ||
2268 | lcs_remove_device(struct ccwgroup_device *ccwgdev) | ||
2269 | { | ||
2270 | struct lcs_card *card; | ||
2271 | |||
2272 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | ||
2273 | if (!card) | ||
2274 | return; | ||
2275 | |||
2276 | PRINT_INFO("Removing lcs group device ....\n"); | ||
2277 | LCS_DBF_TEXT(3, setup, "remdev"); | ||
2278 | LCS_DBF_HEX(3, setup, &card, sizeof(void*)); | ||
2279 | if (ccwgdev->state == CCWGROUP_ONLINE) { | ||
2280 | lcs_shutdown_device(ccwgdev); | ||
2281 | } | ||
2282 | if (card->dev) | ||
2283 | unregister_netdev(card->dev); | ||
2284 | sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group); | ||
2285 | lcs_cleanup_card(card); | ||
2286 | lcs_free_card(card); | ||
2287 | put_device(&ccwgdev->dev); | ||
2288 | } | ||
2289 | |||
2290 | /** | ||
2291 | * LCS ccwgroup driver registration | ||
2292 | */ | ||
2293 | static struct ccwgroup_driver lcs_group_driver = { | ||
2294 | .owner = THIS_MODULE, | ||
2295 | .name = "lcs", | ||
2296 | .max_slaves = 2, | ||
2297 | .driver_id = 0xD3C3E2, | ||
2298 | .probe = lcs_probe_device, | ||
2299 | .remove = lcs_remove_device, | ||
2300 | .set_online = lcs_new_device, | ||
2301 | .set_offline = lcs_shutdown_device, | ||
2302 | }; | ||
2303 | |||
2304 | /** | ||
2305 | * LCS Module/Kernel initialization function | ||
2306 | */ | ||
2307 | static int | ||
2308 | __init lcs_init_module(void) | ||
2309 | { | ||
2310 | int rc; | ||
2311 | |||
2312 | PRINT_INFO("Loading %s\n",version); | ||
2313 | rc = lcs_register_debug_facility(); | ||
2314 | LCS_DBF_TEXT(0, setup, "lcsinit"); | ||
2315 | if (rc) { | ||
2316 | PRINT_ERR("Initialization failed\n"); | ||
2317 | return rc; | ||
2318 | } | ||
2319 | |||
2320 | rc = register_cu3088_discipline(&lcs_group_driver); | ||
2321 | if (rc) { | ||
2322 | PRINT_ERR("Initialization failed\n"); | ||
2323 | return rc; | ||
2324 | } | ||
2325 | |||
2326 | return 0; | ||
2327 | } | ||
2328 | |||
2329 | |||
2330 | /** | ||
2331 | * LCS module cleanup function | ||
2332 | */ | ||
2333 | static void | ||
2334 | __exit lcs_cleanup_module(void) | ||
2335 | { | ||
2336 | PRINT_INFO("Terminating lcs module.\n"); | ||
2337 | LCS_DBF_TEXT(0, trace, "cleanup"); | ||
2338 | unregister_cu3088_discipline(&lcs_group_driver); | ||
2339 | lcs_unregister_debug_facility(); | ||
2340 | } | ||
2341 | |||
2342 | module_init(lcs_init_module); | ||
2343 | module_exit(lcs_cleanup_module); | ||
2344 | |||
2345 | MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>"); | ||
2346 | MODULE_LICENSE("GPL"); | ||
2347 | |||