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