diff options
Diffstat (limited to 'drivers/s390/net/ctcm_mpc.c')
-rw-r--r-- | drivers/s390/net/ctcm_mpc.c | 2472 |
1 files changed, 2472 insertions, 0 deletions
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c new file mode 100644 index 000000000000..044addee64a2 --- /dev/null +++ b/drivers/s390/net/ctcm_mpc.c | |||
@@ -0,0 +1,2472 @@ | |||
1 | /* | ||
2 | * drivers/s390/net/ctcm_mpc.c | ||
3 | * | ||
4 | * Copyright IBM Corp. 2004, 2007 | ||
5 | * Authors: Belinda Thompson (belindat@us.ibm.com) | ||
6 | * Andy Richter (richtera@us.ibm.com) | ||
7 | * Peter Tiedemann (ptiedem@de.ibm.com) | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | This module exports functions to be used by CCS: | ||
12 | EXPORT_SYMBOL(ctc_mpc_alloc_channel); | ||
13 | EXPORT_SYMBOL(ctc_mpc_establish_connectivity); | ||
14 | EXPORT_SYMBOL(ctc_mpc_dealloc_ch); | ||
15 | EXPORT_SYMBOL(ctc_mpc_flow_control); | ||
16 | */ | ||
17 | |||
18 | #undef DEBUG | ||
19 | #undef DEBUGDATA | ||
20 | #undef DEBUGCCW | ||
21 | |||
22 | #include <linux/version.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/types.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/timer.h> | ||
31 | #include <linux/sched.h> | ||
32 | |||
33 | #include <linux/signal.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/proc_fs.h> | ||
36 | |||
37 | #include <linux/ip.h> | ||
38 | #include <linux/if_arp.h> | ||
39 | #include <linux/tcp.h> | ||
40 | #include <linux/skbuff.h> | ||
41 | #include <linux/ctype.h> | ||
42 | #include <linux/netdevice.h> | ||
43 | #include <net/dst.h> | ||
44 | |||
45 | #include <linux/io.h> /* instead of <asm/io.h> ok ? */ | ||
46 | #include <asm/ccwdev.h> | ||
47 | #include <asm/ccwgroup.h> | ||
48 | #include <linux/bitops.h> /* instead of <asm/bitops.h> ok ? */ | ||
49 | #include <linux/uaccess.h> /* instead of <asm/uaccess.h> ok ? */ | ||
50 | #include <linux/wait.h> | ||
51 | #include <linux/moduleparam.h> | ||
52 | #include <asm/idals.h> | ||
53 | |||
54 | #include "cu3088.h" | ||
55 | #include "ctcm_mpc.h" | ||
56 | #include "ctcm_main.h" | ||
57 | #include "ctcm_fsms.h" | ||
58 | |||
59 | static const struct xid2 init_xid = { | ||
60 | .xid2_type_id = XID_FM2, | ||
61 | .xid2_len = 0x45, | ||
62 | .xid2_adj_id = 0, | ||
63 | .xid2_rlen = 0x31, | ||
64 | .xid2_resv1 = 0, | ||
65 | .xid2_flag1 = 0, | ||
66 | .xid2_fmtt = 0, | ||
67 | .xid2_flag4 = 0x80, | ||
68 | .xid2_resv2 = 0, | ||
69 | .xid2_tgnum = 0, | ||
70 | .xid2_sender_id = 0, | ||
71 | .xid2_flag2 = 0, | ||
72 | .xid2_option = XID2_0, | ||
73 | .xid2_resv3 = "\x00", | ||
74 | .xid2_resv4 = 0, | ||
75 | .xid2_dlc_type = XID2_READ_SIDE, | ||
76 | .xid2_resv5 = 0, | ||
77 | .xid2_mpc_flag = 0, | ||
78 | .xid2_resv6 = 0, | ||
79 | .xid2_buf_len = (MPC_BUFSIZE_DEFAULT - 35), | ||
80 | }; | ||
81 | |||
82 | static const struct th_header thnorm = { | ||
83 | .th_seg = 0x00, | ||
84 | .th_ch_flag = TH_IS_XID, | ||
85 | .th_blk_flag = TH_DATA_IS_XID, | ||
86 | .th_is_xid = 0x01, | ||
87 | .th_seq_num = 0x00000000, | ||
88 | }; | ||
89 | |||
90 | static const struct th_header thdummy = { | ||
91 | .th_seg = 0x00, | ||
92 | .th_ch_flag = 0x00, | ||
93 | .th_blk_flag = TH_DATA_IS_XID, | ||
94 | .th_is_xid = 0x01, | ||
95 | .th_seq_num = 0x00000000, | ||
96 | }; | ||
97 | |||
98 | /* | ||
99 | * Definition of one MPC group | ||
100 | */ | ||
101 | |||
102 | /* | ||
103 | * Compatibility macros for busy handling | ||
104 | * of network devices. | ||
105 | */ | ||
106 | |||
107 | static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb); | ||
108 | |||
109 | /* | ||
110 | * MPC Group state machine actions (static prototypes) | ||
111 | */ | ||
112 | static void mpc_action_nop(fsm_instance *fsm, int event, void *arg); | ||
113 | static void mpc_action_go_ready(fsm_instance *fsm, int event, void *arg); | ||
114 | static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg); | ||
115 | static void mpc_action_timeout(fsm_instance *fi, int event, void *arg); | ||
116 | static int mpc_validate_xid(struct mpcg_info *mpcginfo); | ||
117 | static void mpc_action_yside_xid(fsm_instance *fsm, int event, void *arg); | ||
118 | static void mpc_action_doxid0(fsm_instance *fsm, int event, void *arg); | ||
119 | static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg); | ||
120 | static void mpc_action_xside_xid(fsm_instance *fsm, int event, void *arg); | ||
121 | static void mpc_action_rcvd_xid0(fsm_instance *fsm, int event, void *arg); | ||
122 | static void mpc_action_rcvd_xid7(fsm_instance *fsm, int event, void *arg); | ||
123 | |||
124 | #ifdef DEBUGDATA | ||
125 | /*-------------------------------------------------------------------* | ||
126 | * Dump buffer format * | ||
127 | * * | ||
128 | *--------------------------------------------------------------------*/ | ||
129 | void ctcmpc_dumpit(char *buf, int len) | ||
130 | { | ||
131 | __u32 ct, sw, rm, dup; | ||
132 | char *ptr, *rptr; | ||
133 | char tbuf[82], tdup[82]; | ||
134 | #if (UTS_MACHINE == s390x) | ||
135 | char addr[22]; | ||
136 | #else | ||
137 | char addr[12]; | ||
138 | #endif | ||
139 | char boff[12]; | ||
140 | char bhex[82], duphex[82]; | ||
141 | char basc[40]; | ||
142 | |||
143 | sw = 0; | ||
144 | rptr = ptr = buf; | ||
145 | rm = 16; | ||
146 | duphex[0] = 0x00; | ||
147 | dup = 0; | ||
148 | |||
149 | for (ct = 0; ct < len; ct++, ptr++, rptr++) { | ||
150 | if (sw == 0) { | ||
151 | #if (UTS_MACHINE == s390x) | ||
152 | sprintf(addr, "%16.16lx", (unsigned long)rptr); | ||
153 | #else | ||
154 | sprintf(addr, "%8.8X", (__u32)rptr); | ||
155 | #endif | ||
156 | |||
157 | sprintf(boff, "%4.4X", (__u32)ct); | ||
158 | bhex[0] = '\0'; | ||
159 | basc[0] = '\0'; | ||
160 | } | ||
161 | if ((sw == 4) || (sw == 12)) | ||
162 | strcat(bhex, " "); | ||
163 | if (sw == 8) | ||
164 | strcat(bhex, " "); | ||
165 | |||
166 | #if (UTS_MACHINE == s390x) | ||
167 | sprintf(tbuf, "%2.2lX", (unsigned long)*ptr); | ||
168 | #else | ||
169 | sprintf(tbuf, "%2.2X", (__u32)*ptr); | ||
170 | #endif | ||
171 | |||
172 | tbuf[2] = '\0'; | ||
173 | strcat(bhex, tbuf); | ||
174 | if ((0 != isprint(*ptr)) && (*ptr >= 0x20)) | ||
175 | basc[sw] = *ptr; | ||
176 | else | ||
177 | basc[sw] = '.'; | ||
178 | |||
179 | basc[sw+1] = '\0'; | ||
180 | sw++; | ||
181 | rm--; | ||
182 | if (sw == 16) { | ||
183 | if ((strcmp(duphex, bhex)) != 0) { | ||
184 | if (dup != 0) { | ||
185 | sprintf(tdup, "Duplicate as above " | ||
186 | "to %s", addr); | ||
187 | printk(KERN_INFO " " | ||
188 | " --- %s ---\n", tdup); | ||
189 | } | ||
190 | printk(KERN_INFO " %s (+%s) : %s [%s]\n", | ||
191 | addr, boff, bhex, basc); | ||
192 | dup = 0; | ||
193 | strcpy(duphex, bhex); | ||
194 | } else | ||
195 | dup++; | ||
196 | |||
197 | sw = 0; | ||
198 | rm = 16; | ||
199 | } | ||
200 | } /* endfor */ | ||
201 | |||
202 | if (sw != 0) { | ||
203 | for ( ; rm > 0; rm--, sw++) { | ||
204 | if ((sw == 4) || (sw == 12)) | ||
205 | strcat(bhex, " "); | ||
206 | if (sw == 8) | ||
207 | strcat(bhex, " "); | ||
208 | strcat(bhex, " "); | ||
209 | strcat(basc, " "); | ||
210 | } | ||
211 | if (dup != 0) { | ||
212 | sprintf(tdup, "Duplicate as above to %s", addr); | ||
213 | printk(KERN_INFO " " | ||
214 | " --- %s ---\n", tdup); | ||
215 | } | ||
216 | printk(KERN_INFO " %s (+%s) : %s [%s]\n", | ||
217 | addr, boff, bhex, basc); | ||
218 | } else { | ||
219 | if (dup >= 1) { | ||
220 | sprintf(tdup, "Duplicate as above to %s", addr); | ||
221 | printk(KERN_INFO " " | ||
222 | " --- %s ---\n", tdup); | ||
223 | } | ||
224 | if (dup != 0) { | ||
225 | printk(KERN_INFO " %s (+%s) : %s [%s]\n", | ||
226 | addr, boff, bhex, basc); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | return; | ||
231 | |||
232 | } /* end of ctcmpc_dumpit */ | ||
233 | #endif | ||
234 | |||
235 | #ifdef DEBUGDATA | ||
236 | /* | ||
237 | * Dump header and first 16 bytes of an sk_buff for debugging purposes. | ||
238 | * | ||
239 | * skb The sk_buff to dump. | ||
240 | * offset Offset relative to skb-data, where to start the dump. | ||
241 | */ | ||
242 | void ctcmpc_dump_skb(struct sk_buff *skb, int offset) | ||
243 | { | ||
244 | unsigned char *p = skb->data; | ||
245 | struct th_header *header; | ||
246 | struct pdu *pheader; | ||
247 | int bl = skb->len; | ||
248 | int i; | ||
249 | |||
250 | if (p == NULL) | ||
251 | return; | ||
252 | |||
253 | p += offset; | ||
254 | header = (struct th_header *)p; | ||
255 | |||
256 | printk(KERN_INFO "dump:\n"); | ||
257 | printk(KERN_INFO "skb len=%d \n", skb->len); | ||
258 | if (skb->len > 2) { | ||
259 | switch (header->th_ch_flag) { | ||
260 | case TH_HAS_PDU: | ||
261 | break; | ||
262 | case 0x00: | ||
263 | case TH_IS_XID: | ||
264 | if ((header->th_blk_flag == TH_DATA_IS_XID) && | ||
265 | (header->th_is_xid == 0x01)) | ||
266 | goto dumpth; | ||
267 | case TH_SWEEP_REQ: | ||
268 | goto dumpth; | ||
269 | case TH_SWEEP_RESP: | ||
270 | goto dumpth; | ||
271 | default: | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | pheader = (struct pdu *)p; | ||
276 | printk(KERN_INFO "pdu->offset: %d hex: %04x\n", | ||
277 | pheader->pdu_offset, pheader->pdu_offset); | ||
278 | printk(KERN_INFO "pdu->flag : %02x\n", pheader->pdu_flag); | ||
279 | printk(KERN_INFO "pdu->proto : %02x\n", pheader->pdu_proto); | ||
280 | printk(KERN_INFO "pdu->seq : %02x\n", pheader->pdu_seq); | ||
281 | goto dumpdata; | ||
282 | |||
283 | dumpth: | ||
284 | printk(KERN_INFO "th->seg : %02x\n", header->th_seg); | ||
285 | printk(KERN_INFO "th->ch : %02x\n", header->th_ch_flag); | ||
286 | printk(KERN_INFO "th->blk_flag: %02x\n", header->th_blk_flag); | ||
287 | printk(KERN_INFO "th->type : %s\n", | ||
288 | (header->th_is_xid) ? "DATA" : "XID"); | ||
289 | printk(KERN_INFO "th->seqnum : %04x\n", header->th_seq_num); | ||
290 | |||
291 | } | ||
292 | dumpdata: | ||
293 | if (bl > 32) | ||
294 | bl = 32; | ||
295 | printk(KERN_INFO "data: "); | ||
296 | for (i = 0; i < bl; i++) | ||
297 | printk(KERN_INFO "%02x%s", *p++, (i % 16) ? " " : "\n<7>"); | ||
298 | printk(KERN_INFO "\n"); | ||
299 | } | ||
300 | #endif | ||
301 | |||
302 | /* | ||
303 | * ctc_mpc_alloc_channel | ||
304 | * (exported interface) | ||
305 | * | ||
306 | * Device Initialization : | ||
307 | * ACTPATH driven IO operations | ||
308 | */ | ||
309 | int ctc_mpc_alloc_channel(int port_num, void (*callback)(int, int)) | ||
310 | { | ||
311 | char device[20]; | ||
312 | struct net_device *dev; | ||
313 | struct mpc_group *grp; | ||
314 | struct ctcm_priv *priv; | ||
315 | |||
316 | ctcm_pr_debug("ctcmpc enter: %s()\n", __FUNCTION__); | ||
317 | |||
318 | sprintf(device, "%s%i", MPC_DEVICE_NAME, port_num); | ||
319 | dev = __dev_get_by_name(&init_net, device); | ||
320 | |||
321 | if (dev == NULL) { | ||
322 | printk(KERN_INFO "ctc_mpc_alloc_channel %s dev=NULL\n", device); | ||
323 | return 1; | ||
324 | } | ||
325 | |||
326 | priv = dev->priv; | ||
327 | grp = priv->mpcg; | ||
328 | if (!grp) | ||
329 | return 1; | ||
330 | |||
331 | grp->allochanfunc = callback; | ||
332 | grp->port_num = port_num; | ||
333 | grp->port_persist = 1; | ||
334 | |||
335 | ctcm_pr_debug("ctcmpc: %s called for device %s state=%s\n", | ||
336 | __FUNCTION__, | ||
337 | dev->name, | ||
338 | fsm_getstate_str(grp->fsm)); | ||
339 | |||
340 | switch (fsm_getstate(grp->fsm)) { | ||
341 | case MPCG_STATE_INOP: | ||
342 | /* Group is in the process of terminating */ | ||
343 | grp->alloc_called = 1; | ||
344 | break; | ||
345 | case MPCG_STATE_RESET: | ||
346 | /* MPC Group will transition to state */ | ||
347 | /* MPCG_STATE_XID2INITW iff the minimum number */ | ||
348 | /* of 1 read and 1 write channel have successfully*/ | ||
349 | /* activated */ | ||
350 | /*fsm_newstate(grp->fsm, MPCG_STATE_XID2INITW);*/ | ||
351 | if (callback) | ||
352 | grp->send_qllc_disc = 1; | ||
353 | case MPCG_STATE_XID0IOWAIT: | ||
354 | fsm_deltimer(&grp->timer); | ||
355 | grp->outstanding_xid2 = 0; | ||
356 | grp->outstanding_xid7 = 0; | ||
357 | grp->outstanding_xid7_p2 = 0; | ||
358 | grp->saved_xid2 = NULL; | ||
359 | if (callback) | ||
360 | ctcm_open(dev); | ||
361 | fsm_event(priv->fsm, DEV_EVENT_START, dev); | ||
362 | break; | ||
363 | case MPCG_STATE_READY: | ||
364 | /* XID exchanges completed after PORT was activated */ | ||
365 | /* Link station already active */ | ||
366 | /* Maybe timing issue...retry callback */ | ||
367 | grp->allocchan_callback_retries++; | ||
368 | if (grp->allocchan_callback_retries < 4) { | ||
369 | if (grp->allochanfunc) | ||
370 | grp->allochanfunc(grp->port_num, | ||
371 | grp->group_max_buflen); | ||
372 | } else { | ||
373 | /* there are problems...bail out */ | ||
374 | /* there may be a state mismatch so restart */ | ||
375 | grp->port_persist = 1; | ||
376 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
377 | grp->allocchan_callback_retries = 0; | ||
378 | } | ||
379 | break; | ||
380 | default: | ||
381 | return 0; | ||
382 | |||
383 | } | ||
384 | |||
385 | ctcm_pr_debug("ctcmpc exit: %s()\n", __FUNCTION__); | ||
386 | return 0; | ||
387 | } | ||
388 | EXPORT_SYMBOL(ctc_mpc_alloc_channel); | ||
389 | |||
390 | /* | ||
391 | * ctc_mpc_establish_connectivity | ||
392 | * (exported interface) | ||
393 | */ | ||
394 | void ctc_mpc_establish_connectivity(int port_num, | ||
395 | void (*callback)(int, int, int)) | ||
396 | { | ||
397 | char device[20]; | ||
398 | struct net_device *dev; | ||
399 | struct mpc_group *grp; | ||
400 | struct ctcm_priv *priv; | ||
401 | struct channel *rch, *wch; | ||
402 | |||
403 | ctcm_pr_debug("ctcmpc enter: %s()\n", __FUNCTION__); | ||
404 | |||
405 | sprintf(device, "%s%i", MPC_DEVICE_NAME, port_num); | ||
406 | dev = __dev_get_by_name(&init_net, device); | ||
407 | |||
408 | if (dev == NULL) { | ||
409 | printk(KERN_INFO "ctc_mpc_establish_connectivity " | ||
410 | "%s dev=NULL\n", device); | ||
411 | return; | ||
412 | } | ||
413 | priv = dev->priv; | ||
414 | rch = priv->channel[READ]; | ||
415 | wch = priv->channel[WRITE]; | ||
416 | |||
417 | grp = priv->mpcg; | ||
418 | |||
419 | ctcm_pr_debug("ctcmpc: %s() called for device %s state=%s\n", | ||
420 | __FUNCTION__, dev->name, | ||
421 | fsm_getstate_str(grp->fsm)); | ||
422 | |||
423 | grp->estconnfunc = callback; | ||
424 | grp->port_num = port_num; | ||
425 | |||
426 | switch (fsm_getstate(grp->fsm)) { | ||
427 | case MPCG_STATE_READY: | ||
428 | /* XID exchanges completed after PORT was activated */ | ||
429 | /* Link station already active */ | ||
430 | /* Maybe timing issue...retry callback */ | ||
431 | fsm_deltimer(&grp->timer); | ||
432 | grp->estconn_callback_retries++; | ||
433 | if (grp->estconn_callback_retries < 4) { | ||
434 | if (grp->estconnfunc) { | ||
435 | grp->estconnfunc(grp->port_num, 0, | ||
436 | grp->group_max_buflen); | ||
437 | grp->estconnfunc = NULL; | ||
438 | } | ||
439 | } else { | ||
440 | /* there are problems...bail out */ | ||
441 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
442 | grp->estconn_callback_retries = 0; | ||
443 | } | ||
444 | break; | ||
445 | case MPCG_STATE_INOP: | ||
446 | case MPCG_STATE_RESET: | ||
447 | /* MPC Group is not ready to start XID - min num of */ | ||
448 | /* 1 read and 1 write channel have not been acquired*/ | ||
449 | printk(KERN_WARNING "ctcmpc: %s() REJECTED ACTIVE XID Req" | ||
450 | "uest - Channel Pair is not Active\n", __FUNCTION__); | ||
451 | if (grp->estconnfunc) { | ||
452 | grp->estconnfunc(grp->port_num, -1, 0); | ||
453 | grp->estconnfunc = NULL; | ||
454 | } | ||
455 | break; | ||
456 | case MPCG_STATE_XID2INITW: | ||
457 | /* alloc channel was called but no XID exchange */ | ||
458 | /* has occurred. initiate xside XID exchange */ | ||
459 | /* make sure yside XID0 processing has not started */ | ||
460 | if ((fsm_getstate(rch->fsm) > CH_XID0_PENDING) || | ||
461 | (fsm_getstate(wch->fsm) > CH_XID0_PENDING)) { | ||
462 | printk(KERN_WARNING "mpc: %s() ABORT ACTIVE XID" | ||
463 | " Request- PASSIVE XID in process\n" | ||
464 | , __FUNCTION__); | ||
465 | break; | ||
466 | } | ||
467 | grp->send_qllc_disc = 1; | ||
468 | fsm_newstate(grp->fsm, MPCG_STATE_XID0IOWAIT); | ||
469 | fsm_deltimer(&grp->timer); | ||
470 | fsm_addtimer(&grp->timer, MPC_XID_TIMEOUT_VALUE, | ||
471 | MPCG_EVENT_TIMER, dev); | ||
472 | grp->outstanding_xid7 = 0; | ||
473 | grp->outstanding_xid7_p2 = 0; | ||
474 | grp->saved_xid2 = NULL; | ||
475 | if ((rch->in_mpcgroup) && | ||
476 | (fsm_getstate(rch->fsm) == CH_XID0_PENDING)) | ||
477 | fsm_event(grp->fsm, MPCG_EVENT_XID0DO, rch); | ||
478 | else { | ||
479 | printk(KERN_WARNING "mpc: %s() Unable to start" | ||
480 | " ACTIVE XID0 on read channel\n", | ||
481 | __FUNCTION__); | ||
482 | if (grp->estconnfunc) { | ||
483 | grp->estconnfunc(grp->port_num, -1, 0); | ||
484 | grp->estconnfunc = NULL; | ||
485 | } | ||
486 | fsm_deltimer(&grp->timer); | ||
487 | goto done; | ||
488 | } | ||
489 | if ((wch->in_mpcgroup) && | ||
490 | (fsm_getstate(wch->fsm) == CH_XID0_PENDING)) | ||
491 | fsm_event(grp->fsm, MPCG_EVENT_XID0DO, wch); | ||
492 | else { | ||
493 | printk(KERN_WARNING "mpc: %s() Unable to start" | ||
494 | " ACTIVE XID0 on write channel\n", | ||
495 | __FUNCTION__); | ||
496 | if (grp->estconnfunc) { | ||
497 | grp->estconnfunc(grp->port_num, -1, 0); | ||
498 | grp->estconnfunc = NULL; | ||
499 | } | ||
500 | fsm_deltimer(&grp->timer); | ||
501 | goto done; | ||
502 | } | ||
503 | break; | ||
504 | case MPCG_STATE_XID0IOWAIT: | ||
505 | /* already in active XID negotiations */ | ||
506 | default: | ||
507 | break; | ||
508 | } | ||
509 | |||
510 | done: | ||
511 | ctcm_pr_debug("ctcmpc exit: %s()\n", __FUNCTION__); | ||
512 | return; | ||
513 | } | ||
514 | EXPORT_SYMBOL(ctc_mpc_establish_connectivity); | ||
515 | |||
516 | /* | ||
517 | * ctc_mpc_dealloc_ch | ||
518 | * (exported interface) | ||
519 | */ | ||
520 | void ctc_mpc_dealloc_ch(int port_num) | ||
521 | { | ||
522 | struct net_device *dev; | ||
523 | char device[20]; | ||
524 | struct ctcm_priv *priv; | ||
525 | struct mpc_group *grp; | ||
526 | |||
527 | ctcm_pr_debug("ctcmpc enter: %s()\n", __FUNCTION__); | ||
528 | sprintf(device, "%s%i", MPC_DEVICE_NAME, port_num); | ||
529 | dev = __dev_get_by_name(&init_net, device); | ||
530 | |||
531 | if (dev == NULL) { | ||
532 | printk(KERN_INFO "%s() %s dev=NULL\n", __FUNCTION__, device); | ||
533 | goto done; | ||
534 | } | ||
535 | |||
536 | ctcm_pr_debug("ctcmpc:%s %s() called for device %s refcount=%d\n", | ||
537 | dev->name, __FUNCTION__, | ||
538 | dev->name, atomic_read(&dev->refcnt)); | ||
539 | |||
540 | priv = dev->priv; | ||
541 | if (priv == NULL) { | ||
542 | printk(KERN_INFO "%s() %s priv=NULL\n", | ||
543 | __FUNCTION__, device); | ||
544 | goto done; | ||
545 | } | ||
546 | fsm_deltimer(&priv->restart_timer); | ||
547 | |||
548 | grp = priv->mpcg; | ||
549 | if (grp == NULL) { | ||
550 | printk(KERN_INFO "%s() %s dev=NULL\n", __FUNCTION__, device); | ||
551 | goto done; | ||
552 | } | ||
553 | grp->channels_terminating = 0; | ||
554 | |||
555 | fsm_deltimer(&grp->timer); | ||
556 | |||
557 | grp->allochanfunc = NULL; | ||
558 | grp->estconnfunc = NULL; | ||
559 | grp->port_persist = 0; | ||
560 | grp->send_qllc_disc = 0; | ||
561 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
562 | |||
563 | ctcm_close(dev); | ||
564 | done: | ||
565 | ctcm_pr_debug("ctcmpc exit: %s()\n", __FUNCTION__); | ||
566 | return; | ||
567 | } | ||
568 | EXPORT_SYMBOL(ctc_mpc_dealloc_ch); | ||
569 | |||
570 | /* | ||
571 | * ctc_mpc_flow_control | ||
572 | * (exported interface) | ||
573 | */ | ||
574 | void ctc_mpc_flow_control(int port_num, int flowc) | ||
575 | { | ||
576 | char device[20]; | ||
577 | struct ctcm_priv *priv; | ||
578 | struct mpc_group *grp; | ||
579 | struct net_device *dev; | ||
580 | struct channel *rch; | ||
581 | int mpcg_state; | ||
582 | |||
583 | ctcm_pr_debug("ctcmpc enter: %s() %i\n", __FUNCTION__, flowc); | ||
584 | |||
585 | sprintf(device, "%s%i", MPC_DEVICE_NAME, port_num); | ||
586 | dev = __dev_get_by_name(&init_net, device); | ||
587 | |||
588 | if (dev == NULL) { | ||
589 | printk(KERN_INFO "ctc_mpc_flow_control %s dev=NULL\n", device); | ||
590 | return; | ||
591 | } | ||
592 | |||
593 | ctcm_pr_debug("ctcmpc: %s %s called \n", dev->name, __FUNCTION__); | ||
594 | |||
595 | priv = dev->priv; | ||
596 | if (priv == NULL) { | ||
597 | printk(KERN_INFO "ctcmpc:%s() %s priv=NULL\n", | ||
598 | __FUNCTION__, device); | ||
599 | return; | ||
600 | } | ||
601 | grp = priv->mpcg; | ||
602 | rch = priv->channel[READ]; | ||
603 | |||
604 | mpcg_state = fsm_getstate(grp->fsm); | ||
605 | switch (flowc) { | ||
606 | case 1: | ||
607 | if (mpcg_state == MPCG_STATE_FLOWC) | ||
608 | break; | ||
609 | if (mpcg_state == MPCG_STATE_READY) { | ||
610 | if (grp->flow_off_called == 1) | ||
611 | grp->flow_off_called = 0; | ||
612 | else | ||
613 | fsm_newstate(grp->fsm, MPCG_STATE_FLOWC); | ||
614 | break; | ||
615 | } | ||
616 | break; | ||
617 | case 0: | ||
618 | if (mpcg_state == MPCG_STATE_FLOWC) { | ||
619 | fsm_newstate(grp->fsm, MPCG_STATE_READY); | ||
620 | /* ensure any data that has accumulated */ | ||
621 | /* on the io_queue will now be sen t */ | ||
622 | tasklet_schedule(&rch->ch_tasklet); | ||
623 | } | ||
624 | /* possible race condition */ | ||
625 | if (mpcg_state == MPCG_STATE_READY) { | ||
626 | grp->flow_off_called = 1; | ||
627 | break; | ||
628 | } | ||
629 | break; | ||
630 | } | ||
631 | |||
632 | ctcm_pr_debug("ctcmpc exit: %s() %i\n", __FUNCTION__, flowc); | ||
633 | } | ||
634 | EXPORT_SYMBOL(ctc_mpc_flow_control); | ||
635 | |||
636 | static int mpc_send_qllc_discontact(struct net_device *); | ||
637 | |||
638 | /* | ||
639 | * helper function of ctcmpc_unpack_skb | ||
640 | */ | ||
641 | static void mpc_rcvd_sweep_resp(struct mpcg_info *mpcginfo) | ||
642 | { | ||
643 | struct channel *rch = mpcginfo->ch; | ||
644 | struct net_device *dev = rch->netdev; | ||
645 | struct ctcm_priv *priv = dev->priv; | ||
646 | struct mpc_group *grp = priv->mpcg; | ||
647 | struct channel *ch = priv->channel[WRITE]; | ||
648 | |||
649 | if (do_debug) | ||
650 | ctcm_pr_debug("ctcmpc enter: %s(): ch=0x%p id=%s\n", | ||
651 | __FUNCTION__, ch, ch->id); | ||
652 | |||
653 | if (do_debug_data) | ||
654 | ctcmpc_dumpit((char *)mpcginfo->sweep, TH_SWEEP_LENGTH); | ||
655 | |||
656 | grp->sweep_rsp_pend_num--; | ||
657 | |||
658 | if ((grp->sweep_req_pend_num == 0) && | ||
659 | (grp->sweep_rsp_pend_num == 0)) { | ||
660 | fsm_deltimer(&ch->sweep_timer); | ||
661 | grp->in_sweep = 0; | ||
662 | rch->th_seq_num = 0x00; | ||
663 | ch->th_seq_num = 0x00; | ||
664 | ctcm_clear_busy_do(dev); | ||
665 | } | ||
666 | |||
667 | kfree(mpcginfo); | ||
668 | |||
669 | return; | ||
670 | |||
671 | } | ||
672 | |||
673 | /* | ||
674 | * helper function of mpc_rcvd_sweep_req | ||
675 | * which is a helper of ctcmpc_unpack_skb | ||
676 | */ | ||
677 | static void ctcmpc_send_sweep_resp(struct channel *rch) | ||
678 | { | ||
679 | struct net_device *dev = rch->netdev; | ||
680 | struct ctcm_priv *priv = dev->priv; | ||
681 | struct mpc_group *grp = priv->mpcg; | ||
682 | int rc = 0; | ||
683 | struct th_sweep *header; | ||
684 | struct sk_buff *sweep_skb; | ||
685 | struct channel *ch = priv->channel[WRITE]; | ||
686 | |||
687 | if (do_debug) | ||
688 | ctcm_pr_debug("ctcmpc exit : %s(): ch=0x%p id=%s\n", | ||
689 | __FUNCTION__, rch, rch->id); | ||
690 | |||
691 | sweep_skb = __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, | ||
692 | GFP_ATOMIC|GFP_DMA); | ||
693 | if (sweep_skb == NULL) { | ||
694 | printk(KERN_INFO "Couldn't alloc sweep_skb\n"); | ||
695 | rc = -ENOMEM; | ||
696 | goto done; | ||
697 | } | ||
698 | |||
699 | header = (struct th_sweep *) | ||
700 | kmalloc(sizeof(struct th_sweep), gfp_type()); | ||
701 | |||
702 | if (!header) { | ||
703 | dev_kfree_skb_any(sweep_skb); | ||
704 | rc = -ENOMEM; | ||
705 | goto done; | ||
706 | } | ||
707 | |||
708 | header->th.th_seg = 0x00 ; | ||
709 | header->th.th_ch_flag = TH_SWEEP_RESP; | ||
710 | header->th.th_blk_flag = 0x00; | ||
711 | header->th.th_is_xid = 0x00; | ||
712 | header->th.th_seq_num = 0x00; | ||
713 | header->sw.th_last_seq = ch->th_seq_num; | ||
714 | |||
715 | memcpy(skb_put(sweep_skb, TH_SWEEP_LENGTH), header, TH_SWEEP_LENGTH); | ||
716 | |||
717 | kfree(header); | ||
718 | |||
719 | dev->trans_start = jiffies; | ||
720 | skb_queue_tail(&ch->sweep_queue, sweep_skb); | ||
721 | |||
722 | fsm_addtimer(&ch->sweep_timer, 100, CTC_EVENT_RSWEEP_TIMER, ch); | ||
723 | |||
724 | return; | ||
725 | |||
726 | done: | ||
727 | if (rc != 0) { | ||
728 | grp->in_sweep = 0; | ||
729 | ctcm_clear_busy_do(dev); | ||
730 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
731 | } | ||
732 | |||
733 | return; | ||
734 | } | ||
735 | |||
736 | /* | ||
737 | * helper function of ctcmpc_unpack_skb | ||
738 | */ | ||
739 | static void mpc_rcvd_sweep_req(struct mpcg_info *mpcginfo) | ||
740 | { | ||
741 | struct channel *rch = mpcginfo->ch; | ||
742 | struct net_device *dev = rch->netdev; | ||
743 | struct ctcm_priv *priv = dev->priv; | ||
744 | struct mpc_group *grp = priv->mpcg; | ||
745 | struct channel *ch = priv->channel[WRITE]; | ||
746 | |||
747 | if (do_debug) | ||
748 | CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_DEBUG, | ||
749 | " %s(): ch=0x%p id=%s\n", __FUNCTION__, ch, ch->id); | ||
750 | |||
751 | if (grp->in_sweep == 0) { | ||
752 | grp->in_sweep = 1; | ||
753 | ctcm_test_and_set_busy(dev); | ||
754 | grp->sweep_req_pend_num = grp->active_channels[READ]; | ||
755 | grp->sweep_rsp_pend_num = grp->active_channels[READ]; | ||
756 | } | ||
757 | |||
758 | if (do_debug_data) | ||
759 | ctcmpc_dumpit((char *)mpcginfo->sweep, TH_SWEEP_LENGTH); | ||
760 | |||
761 | grp->sweep_req_pend_num--; | ||
762 | ctcmpc_send_sweep_resp(ch); | ||
763 | kfree(mpcginfo); | ||
764 | return; | ||
765 | } | ||
766 | |||
767 | /* | ||
768 | * MPC Group Station FSM definitions | ||
769 | */ | ||
770 | static const char *mpcg_event_names[] = { | ||
771 | [MPCG_EVENT_INOP] = "INOP Condition", | ||
772 | [MPCG_EVENT_DISCONC] = "Discontact Received", | ||
773 | [MPCG_EVENT_XID0DO] = "Channel Active - Start XID", | ||
774 | [MPCG_EVENT_XID2] = "XID2 Received", | ||
775 | [MPCG_EVENT_XID2DONE] = "XID0 Complete", | ||
776 | [MPCG_EVENT_XID7DONE] = "XID7 Complete", | ||
777 | [MPCG_EVENT_TIMER] = "XID Setup Timer", | ||
778 | [MPCG_EVENT_DOIO] = "XID DoIO", | ||
779 | }; | ||
780 | |||
781 | static const char *mpcg_state_names[] = { | ||
782 | [MPCG_STATE_RESET] = "Reset", | ||
783 | [MPCG_STATE_INOP] = "INOP", | ||
784 | [MPCG_STATE_XID2INITW] = "Passive XID- XID0 Pending Start", | ||
785 | [MPCG_STATE_XID2INITX] = "Passive XID- XID0 Pending Complete", | ||
786 | [MPCG_STATE_XID7INITW] = "Passive XID- XID7 Pending P1 Start", | ||
787 | [MPCG_STATE_XID7INITX] = "Passive XID- XID7 Pending P2 Complete", | ||
788 | [MPCG_STATE_XID0IOWAIT] = "Active XID- XID0 Pending Start", | ||
789 | [MPCG_STATE_XID0IOWAIX] = "Active XID- XID0 Pending Complete", | ||
790 | [MPCG_STATE_XID7INITI] = "Active XID- XID7 Pending Start", | ||
791 | [MPCG_STATE_XID7INITZ] = "Active XID- XID7 Pending Complete ", | ||
792 | [MPCG_STATE_XID7INITF] = "XID - XID7 Complete ", | ||
793 | [MPCG_STATE_FLOWC] = "FLOW CONTROL ON", | ||
794 | [MPCG_STATE_READY] = "READY", | ||
795 | }; | ||
796 | |||
797 | /* | ||
798 | * The MPC Group Station FSM | ||
799 | * 22 events | ||
800 | */ | ||
801 | static const fsm_node mpcg_fsm[] = { | ||
802 | { MPCG_STATE_RESET, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
803 | { MPCG_STATE_INOP, MPCG_EVENT_INOP, mpc_action_nop }, | ||
804 | { MPCG_STATE_FLOWC, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
805 | |||
806 | { MPCG_STATE_READY, MPCG_EVENT_DISCONC, mpc_action_discontact }, | ||
807 | { MPCG_STATE_READY, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
808 | |||
809 | { MPCG_STATE_XID2INITW, MPCG_EVENT_XID0DO, mpc_action_doxid0 }, | ||
810 | { MPCG_STATE_XID2INITW, MPCG_EVENT_XID2, mpc_action_rcvd_xid0 }, | ||
811 | { MPCG_STATE_XID2INITW, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
812 | { MPCG_STATE_XID2INITW, MPCG_EVENT_TIMER, mpc_action_timeout }, | ||
813 | { MPCG_STATE_XID2INITW, MPCG_EVENT_DOIO, mpc_action_yside_xid }, | ||
814 | |||
815 | { MPCG_STATE_XID2INITX, MPCG_EVENT_XID0DO, mpc_action_doxid0 }, | ||
816 | { MPCG_STATE_XID2INITX, MPCG_EVENT_XID2, mpc_action_rcvd_xid0 }, | ||
817 | { MPCG_STATE_XID2INITX, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
818 | { MPCG_STATE_XID2INITX, MPCG_EVENT_TIMER, mpc_action_timeout }, | ||
819 | { MPCG_STATE_XID2INITX, MPCG_EVENT_DOIO, mpc_action_yside_xid }, | ||
820 | |||
821 | { MPCG_STATE_XID7INITW, MPCG_EVENT_XID2DONE, mpc_action_doxid7 }, | ||
822 | { MPCG_STATE_XID7INITW, MPCG_EVENT_DISCONC, mpc_action_discontact }, | ||
823 | { MPCG_STATE_XID7INITW, MPCG_EVENT_XID2, mpc_action_rcvd_xid7 }, | ||
824 | { MPCG_STATE_XID7INITW, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
825 | { MPCG_STATE_XID7INITW, MPCG_EVENT_TIMER, mpc_action_timeout }, | ||
826 | { MPCG_STATE_XID7INITW, MPCG_EVENT_XID7DONE, mpc_action_doxid7 }, | ||
827 | { MPCG_STATE_XID7INITW, MPCG_EVENT_DOIO, mpc_action_yside_xid }, | ||
828 | |||
829 | { MPCG_STATE_XID7INITX, MPCG_EVENT_DISCONC, mpc_action_discontact }, | ||
830 | { MPCG_STATE_XID7INITX, MPCG_EVENT_XID2, mpc_action_rcvd_xid7 }, | ||
831 | { MPCG_STATE_XID7INITX, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
832 | { MPCG_STATE_XID7INITX, MPCG_EVENT_XID7DONE, mpc_action_doxid7 }, | ||
833 | { MPCG_STATE_XID7INITX, MPCG_EVENT_TIMER, mpc_action_timeout }, | ||
834 | { MPCG_STATE_XID7INITX, MPCG_EVENT_DOIO, mpc_action_yside_xid }, | ||
835 | |||
836 | { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_XID0DO, mpc_action_doxid0 }, | ||
837 | { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_DISCONC, mpc_action_discontact }, | ||
838 | { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_XID2, mpc_action_rcvd_xid0 }, | ||
839 | { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
840 | { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_TIMER, mpc_action_timeout }, | ||
841 | { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_DOIO, mpc_action_xside_xid }, | ||
842 | |||
843 | { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_XID0DO, mpc_action_doxid0 }, | ||
844 | { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_DISCONC, mpc_action_discontact }, | ||
845 | { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_XID2, mpc_action_rcvd_xid0 }, | ||
846 | { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
847 | { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_TIMER, mpc_action_timeout }, | ||
848 | { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_DOIO, mpc_action_xside_xid }, | ||
849 | |||
850 | { MPCG_STATE_XID7INITI, MPCG_EVENT_XID2DONE, mpc_action_doxid7 }, | ||
851 | { MPCG_STATE_XID7INITI, MPCG_EVENT_XID2, mpc_action_rcvd_xid7 }, | ||
852 | { MPCG_STATE_XID7INITI, MPCG_EVENT_DISCONC, mpc_action_discontact }, | ||
853 | { MPCG_STATE_XID7INITI, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
854 | { MPCG_STATE_XID7INITI, MPCG_EVENT_TIMER, mpc_action_timeout }, | ||
855 | { MPCG_STATE_XID7INITI, MPCG_EVENT_XID7DONE, mpc_action_doxid7 }, | ||
856 | { MPCG_STATE_XID7INITI, MPCG_EVENT_DOIO, mpc_action_xside_xid }, | ||
857 | |||
858 | { MPCG_STATE_XID7INITZ, MPCG_EVENT_XID2, mpc_action_rcvd_xid7 }, | ||
859 | { MPCG_STATE_XID7INITZ, MPCG_EVENT_XID7DONE, mpc_action_doxid7 }, | ||
860 | { MPCG_STATE_XID7INITZ, MPCG_EVENT_DISCONC, mpc_action_discontact }, | ||
861 | { MPCG_STATE_XID7INITZ, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
862 | { MPCG_STATE_XID7INITZ, MPCG_EVENT_TIMER, mpc_action_timeout }, | ||
863 | { MPCG_STATE_XID7INITZ, MPCG_EVENT_DOIO, mpc_action_xside_xid }, | ||
864 | |||
865 | { MPCG_STATE_XID7INITF, MPCG_EVENT_INOP, mpc_action_go_inop }, | ||
866 | { MPCG_STATE_XID7INITF, MPCG_EVENT_XID7DONE, mpc_action_go_ready }, | ||
867 | }; | ||
868 | |||
869 | static int mpcg_fsm_len = ARRAY_SIZE(mpcg_fsm); | ||
870 | |||
871 | /* | ||
872 | * MPC Group Station FSM action | ||
873 | * CTCM_PROTO_MPC only | ||
874 | */ | ||
875 | static void mpc_action_go_ready(fsm_instance *fsm, int event, void *arg) | ||
876 | { | ||
877 | struct net_device *dev = arg; | ||
878 | struct ctcm_priv *priv = NULL; | ||
879 | struct mpc_group *grp = NULL; | ||
880 | |||
881 | if (dev == NULL) { | ||
882 | printk(KERN_INFO "%s() dev=NULL\n", __FUNCTION__); | ||
883 | return; | ||
884 | } | ||
885 | |||
886 | ctcm_pr_debug("ctcmpc enter: %s %s()\n", dev->name, __FUNCTION__); | ||
887 | |||
888 | priv = dev->priv; | ||
889 | if (priv == NULL) { | ||
890 | printk(KERN_INFO "%s() priv=NULL\n", __FUNCTION__); | ||
891 | return; | ||
892 | } | ||
893 | |||
894 | grp = priv->mpcg; | ||
895 | if (grp == NULL) { | ||
896 | printk(KERN_INFO "%s() grp=NULL\n", __FUNCTION__); | ||
897 | return; | ||
898 | } | ||
899 | |||
900 | fsm_deltimer(&grp->timer); | ||
901 | |||
902 | if (grp->saved_xid2->xid2_flag2 == 0x40) { | ||
903 | priv->xid->xid2_flag2 = 0x00; | ||
904 | if (grp->estconnfunc) { | ||
905 | grp->estconnfunc(grp->port_num, 1, | ||
906 | grp->group_max_buflen); | ||
907 | grp->estconnfunc = NULL; | ||
908 | } else if (grp->allochanfunc) | ||
909 | grp->send_qllc_disc = 1; | ||
910 | goto done; | ||
911 | } | ||
912 | |||
913 | grp->port_persist = 1; | ||
914 | grp->out_of_sequence = 0; | ||
915 | grp->estconn_called = 0; | ||
916 | |||
917 | tasklet_hi_schedule(&grp->mpc_tasklet2); | ||
918 | |||
919 | ctcm_pr_debug("ctcmpc exit: %s %s()\n", dev->name, __FUNCTION__); | ||
920 | return; | ||
921 | |||
922 | done: | ||
923 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
924 | |||
925 | |||
926 | ctcm_pr_info("ctcmpc: %s()failure occurred\n", __FUNCTION__); | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * helper of ctcm_init_netdevice | ||
931 | * CTCM_PROTO_MPC only | ||
932 | */ | ||
933 | void mpc_group_ready(unsigned long adev) | ||
934 | { | ||
935 | struct net_device *dev = (struct net_device *)adev; | ||
936 | struct ctcm_priv *priv = NULL; | ||
937 | struct mpc_group *grp = NULL; | ||
938 | struct channel *ch = NULL; | ||
939 | |||
940 | |||
941 | ctcm_pr_debug("ctcmpc enter: %s()\n", __FUNCTION__); | ||
942 | |||
943 | if (dev == NULL) { | ||
944 | printk(KERN_INFO "%s() dev=NULL\n", __FUNCTION__); | ||
945 | return; | ||
946 | } | ||
947 | |||
948 | priv = dev->priv; | ||
949 | if (priv == NULL) { | ||
950 | printk(KERN_INFO "%s() priv=NULL\n", __FUNCTION__); | ||
951 | return; | ||
952 | } | ||
953 | |||
954 | grp = priv->mpcg; | ||
955 | if (grp == NULL) { | ||
956 | printk(KERN_INFO "ctcmpc:%s() grp=NULL\n", __FUNCTION__); | ||
957 | return; | ||
958 | } | ||
959 | |||
960 | printk(KERN_NOTICE "ctcmpc: %s GROUP TRANSITIONED TO READY" | ||
961 | " maxbuf:%d\n", | ||
962 | dev->name, grp->group_max_buflen); | ||
963 | |||
964 | fsm_newstate(grp->fsm, MPCG_STATE_READY); | ||
965 | |||
966 | /* Put up a read on the channel */ | ||
967 | ch = priv->channel[READ]; | ||
968 | ch->pdu_seq = 0; | ||
969 | if (do_debug_data) | ||
970 | ctcm_pr_debug("ctcmpc: %s() ToDCM_pdu_seq= %08x\n" , | ||
971 | __FUNCTION__, ch->pdu_seq); | ||
972 | |||
973 | ctcmpc_chx_rxidle(ch->fsm, CTC_EVENT_START, ch); | ||
974 | /* Put the write channel in idle state */ | ||
975 | ch = priv->channel[WRITE]; | ||
976 | if (ch->collect_len > 0) { | ||
977 | spin_lock(&ch->collect_lock); | ||
978 | ctcm_purge_skb_queue(&ch->collect_queue); | ||
979 | ch->collect_len = 0; | ||
980 | spin_unlock(&ch->collect_lock); | ||
981 | } | ||
982 | ctcm_chx_txidle(ch->fsm, CTC_EVENT_START, ch); | ||
983 | |||
984 | ctcm_clear_busy(dev); | ||
985 | |||
986 | if (grp->estconnfunc) { | ||
987 | grp->estconnfunc(grp->port_num, 0, | ||
988 | grp->group_max_buflen); | ||
989 | grp->estconnfunc = NULL; | ||
990 | } else | ||
991 | if (grp->allochanfunc) | ||
992 | grp->allochanfunc(grp->port_num, | ||
993 | grp->group_max_buflen); | ||
994 | |||
995 | grp->send_qllc_disc = 1; | ||
996 | grp->changed_side = 0; | ||
997 | |||
998 | ctcm_pr_debug("ctcmpc exit: %s()\n", __FUNCTION__); | ||
999 | return; | ||
1000 | |||
1001 | } | ||
1002 | |||
1003 | /* | ||
1004 | * Increment the MPC Group Active Channel Counts | ||
1005 | * helper of dev_action (called from channel fsm) | ||
1006 | */ | ||
1007 | int mpc_channel_action(struct channel *ch, int direction, int action) | ||
1008 | { | ||
1009 | struct net_device *dev = ch->netdev; | ||
1010 | struct ctcm_priv *priv; | ||
1011 | struct mpc_group *grp = NULL; | ||
1012 | int rc = 0; | ||
1013 | |||
1014 | if (do_debug) | ||
1015 | ctcm_pr_debug("ctcmpc enter: %s(): ch=0x%p id=%s\n", | ||
1016 | __FUNCTION__, ch, ch->id); | ||
1017 | |||
1018 | if (dev == NULL) { | ||
1019 | printk(KERN_INFO "ctcmpc_channel_action %i dev=NULL\n", | ||
1020 | action); | ||
1021 | rc = 1; | ||
1022 | goto done; | ||
1023 | } | ||
1024 | |||
1025 | priv = dev->priv; | ||
1026 | if (priv == NULL) { | ||
1027 | printk(KERN_INFO | ||
1028 | "ctcmpc_channel_action%i priv=NULL, dev=%s\n", | ||
1029 | action, dev->name); | ||
1030 | rc = 2; | ||
1031 | goto done; | ||
1032 | } | ||
1033 | |||
1034 | grp = priv->mpcg; | ||
1035 | |||
1036 | if (grp == NULL) { | ||
1037 | printk(KERN_INFO "ctcmpc: %s()%i mpcgroup=NULL, dev=%s\n", | ||
1038 | __FUNCTION__, action, dev->name); | ||
1039 | rc = 3; | ||
1040 | goto done; | ||
1041 | } | ||
1042 | |||
1043 | ctcm_pr_info( | ||
1044 | "ctcmpc: %s() %i(): Grp:%s total_channel_paths=%i " | ||
1045 | "active_channels read=%i, write=%i\n", | ||
1046 | __FUNCTION__, | ||
1047 | action, | ||
1048 | fsm_getstate_str(grp->fsm), | ||
1049 | grp->num_channel_paths, | ||
1050 | grp->active_channels[READ], | ||
1051 | grp->active_channels[WRITE]); | ||
1052 | |||
1053 | if ((action == MPC_CHANNEL_ADD) && (ch->in_mpcgroup == 0)) { | ||
1054 | grp->num_channel_paths++; | ||
1055 | grp->active_channels[direction]++; | ||
1056 | grp->outstanding_xid2++; | ||
1057 | ch->in_mpcgroup = 1; | ||
1058 | |||
1059 | if (ch->xid_skb != NULL) | ||
1060 | dev_kfree_skb_any(ch->xid_skb); | ||
1061 | |||
1062 | ch->xid_skb = __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, | ||
1063 | GFP_ATOMIC | GFP_DMA); | ||
1064 | if (ch->xid_skb == NULL) { | ||
1065 | printk(KERN_INFO "ctcmpc: %s()" | ||
1066 | "Couldn't alloc ch xid_skb\n", __FUNCTION__); | ||
1067 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
1068 | return 1; | ||
1069 | } | ||
1070 | ch->xid_skb_data = ch->xid_skb->data; | ||
1071 | ch->xid_th = (struct th_header *)ch->xid_skb->data; | ||
1072 | skb_put(ch->xid_skb, TH_HEADER_LENGTH); | ||
1073 | ch->xid = (struct xid2 *)skb_tail_pointer(ch->xid_skb); | ||
1074 | skb_put(ch->xid_skb, XID2_LENGTH); | ||
1075 | ch->xid_id = skb_tail_pointer(ch->xid_skb); | ||
1076 | ch->xid_skb->data = ch->xid_skb_data; | ||
1077 | skb_reset_tail_pointer(ch->xid_skb); | ||
1078 | ch->xid_skb->len = 0; | ||
1079 | |||
1080 | memcpy(skb_put(ch->xid_skb, grp->xid_skb->len), | ||
1081 | grp->xid_skb->data, | ||
1082 | grp->xid_skb->len); | ||
1083 | |||
1084 | ch->xid->xid2_dlc_type = ((CHANNEL_DIRECTION(ch->flags) == READ) | ||
1085 | ? XID2_READ_SIDE : XID2_WRITE_SIDE); | ||
1086 | |||
1087 | if (CHANNEL_DIRECTION(ch->flags) == WRITE) | ||
1088 | ch->xid->xid2_buf_len = 0x00; | ||
1089 | |||
1090 | ch->xid_skb->data = ch->xid_skb_data; | ||
1091 | skb_reset_tail_pointer(ch->xid_skb); | ||
1092 | ch->xid_skb->len = 0; | ||
1093 | |||
1094 | fsm_newstate(ch->fsm, CH_XID0_PENDING); | ||
1095 | |||
1096 | if ((grp->active_channels[READ] > 0) && | ||
1097 | (grp->active_channels[WRITE] > 0) && | ||
1098 | (fsm_getstate(grp->fsm) < MPCG_STATE_XID2INITW)) { | ||
1099 | fsm_newstate(grp->fsm, MPCG_STATE_XID2INITW); | ||
1100 | printk(KERN_NOTICE "ctcmpc: %s MPC GROUP " | ||
1101 | "CHANNELS ACTIVE\n", dev->name); | ||
1102 | } | ||
1103 | } else if ((action == MPC_CHANNEL_REMOVE) && | ||
1104 | (ch->in_mpcgroup == 1)) { | ||
1105 | ch->in_mpcgroup = 0; | ||
1106 | grp->num_channel_paths--; | ||
1107 | grp->active_channels[direction]--; | ||
1108 | |||
1109 | if (ch->xid_skb != NULL) | ||
1110 | dev_kfree_skb_any(ch->xid_skb); | ||
1111 | ch->xid_skb = NULL; | ||
1112 | |||
1113 | if (grp->channels_terminating) | ||
1114 | goto done; | ||
1115 | |||
1116 | if (((grp->active_channels[READ] == 0) && | ||
1117 | (grp->active_channels[WRITE] > 0)) | ||
1118 | || ((grp->active_channels[WRITE] == 0) && | ||
1119 | (grp->active_channels[READ] > 0))) | ||
1120 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
1121 | } | ||
1122 | |||
1123 | done: | ||
1124 | |||
1125 | if (do_debug) { | ||
1126 | ctcm_pr_debug( | ||
1127 | "ctcmpc: %s() %i Grp:%s ttl_chan_paths=%i " | ||
1128 | "active_chans read=%i, write=%i\n", | ||
1129 | __FUNCTION__, | ||
1130 | action, | ||
1131 | fsm_getstate_str(grp->fsm), | ||
1132 | grp->num_channel_paths, | ||
1133 | grp->active_channels[READ], | ||
1134 | grp->active_channels[WRITE]); | ||
1135 | |||
1136 | ctcm_pr_debug("ctcmpc exit : %s(): ch=0x%p id=%s\n", | ||
1137 | __FUNCTION__, ch, ch->id); | ||
1138 | } | ||
1139 | return rc; | ||
1140 | |||
1141 | } | ||
1142 | |||
1143 | /** | ||
1144 | * Unpack a just received skb and hand it over to | ||
1145 | * upper layers. | ||
1146 | * special MPC version of unpack_skb. | ||
1147 | * | ||
1148 | * ch The channel where this skb has been received. | ||
1149 | * pskb The received skb. | ||
1150 | */ | ||
1151 | static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb) | ||
1152 | { | ||
1153 | struct net_device *dev = ch->netdev; | ||
1154 | struct ctcm_priv *priv = dev->priv; | ||
1155 | struct mpc_group *grp = priv->mpcg; | ||
1156 | struct pdu *curr_pdu; | ||
1157 | struct mpcg_info *mpcginfo; | ||
1158 | struct th_header *header = NULL; | ||
1159 | struct th_sweep *sweep = NULL; | ||
1160 | int pdu_last_seen = 0; | ||
1161 | __u32 new_len; | ||
1162 | struct sk_buff *skb; | ||
1163 | int skblen; | ||
1164 | int sendrc = 0; | ||
1165 | |||
1166 | if (do_debug) | ||
1167 | ctcm_pr_debug("ctcmpc enter: %s() %s cp:%i ch:%s\n", | ||
1168 | __FUNCTION__, dev->name, smp_processor_id(), ch->id); | ||
1169 | |||
1170 | header = (struct th_header *)pskb->data; | ||
1171 | if ((header->th_seg == 0) && | ||
1172 | (header->th_ch_flag == 0) && | ||
1173 | (header->th_blk_flag == 0) && | ||
1174 | (header->th_seq_num == 0)) | ||
1175 | /* nothing for us */ goto done; | ||
1176 | |||
1177 | if (do_debug_data) { | ||
1178 | ctcm_pr_debug("ctcmpc: %s() th_header\n", __FUNCTION__); | ||
1179 | ctcmpc_dumpit((char *)header, TH_HEADER_LENGTH); | ||
1180 | ctcm_pr_debug("ctcmpc: %s() pskb len: %04x \n", | ||
1181 | __FUNCTION__, pskb->len); | ||
1182 | } | ||
1183 | |||
1184 | pskb->dev = dev; | ||
1185 | pskb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1186 | skb_pull(pskb, TH_HEADER_LENGTH); | ||
1187 | |||
1188 | if (likely(header->th_ch_flag == TH_HAS_PDU)) { | ||
1189 | if (do_debug_data) | ||
1190 | ctcm_pr_debug("ctcmpc: %s() came into th_has_pdu\n", | ||
1191 | __FUNCTION__); | ||
1192 | if ((fsm_getstate(grp->fsm) == MPCG_STATE_FLOWC) || | ||
1193 | ((fsm_getstate(grp->fsm) == MPCG_STATE_READY) && | ||
1194 | (header->th_seq_num != ch->th_seq_num + 1) && | ||
1195 | (ch->th_seq_num != 0))) { | ||
1196 | /* This is NOT the next segment * | ||
1197 | * we are not the correct race winner * | ||
1198 | * go away and let someone else win * | ||
1199 | * BUT..this only applies if xid negot * | ||
1200 | * is done * | ||
1201 | */ | ||
1202 | grp->out_of_sequence += 1; | ||
1203 | __skb_push(pskb, TH_HEADER_LENGTH); | ||
1204 | skb_queue_tail(&ch->io_queue, pskb); | ||
1205 | if (do_debug_data) | ||
1206 | ctcm_pr_debug("ctcmpc: %s() th_seq_num " | ||
1207 | "expect:%08x got:%08x\n", __FUNCTION__, | ||
1208 | ch->th_seq_num + 1, header->th_seq_num); | ||
1209 | |||
1210 | return; | ||
1211 | } | ||
1212 | grp->out_of_sequence = 0; | ||
1213 | ch->th_seq_num = header->th_seq_num; | ||
1214 | |||
1215 | if (do_debug_data) | ||
1216 | ctcm_pr_debug("ctcmpc: %s() FromVTAM_th_seq=%08x\n", | ||
1217 | __FUNCTION__, ch->th_seq_num); | ||
1218 | |||
1219 | if (unlikely(fsm_getstate(grp->fsm) != MPCG_STATE_READY)) | ||
1220 | goto done; | ||
1221 | pdu_last_seen = 0; | ||
1222 | while ((pskb->len > 0) && !pdu_last_seen) { | ||
1223 | curr_pdu = (struct pdu *)pskb->data; | ||
1224 | if (do_debug_data) { | ||
1225 | ctcm_pr_debug("ctcm: %s() pdu_header\n", | ||
1226 | __FUNCTION__); | ||
1227 | ctcmpc_dumpit((char *)pskb->data, | ||
1228 | PDU_HEADER_LENGTH); | ||
1229 | ctcm_pr_debug("ctcm: %s() pskb len: %04x \n", | ||
1230 | __FUNCTION__, pskb->len); | ||
1231 | } | ||
1232 | skb_pull(pskb, PDU_HEADER_LENGTH); | ||
1233 | |||
1234 | if (curr_pdu->pdu_flag & PDU_LAST) | ||
1235 | pdu_last_seen = 1; | ||
1236 | if (curr_pdu->pdu_flag & PDU_CNTL) | ||
1237 | pskb->protocol = htons(ETH_P_SNAP); | ||
1238 | else | ||
1239 | pskb->protocol = htons(ETH_P_SNA_DIX); | ||
1240 | |||
1241 | if ((pskb->len <= 0) || (pskb->len > ch->max_bufsize)) { | ||
1242 | printk(KERN_INFO | ||
1243 | "%s Illegal packet size %d " | ||
1244 | "received " | ||
1245 | "dropping\n", dev->name, | ||
1246 | pskb->len); | ||
1247 | priv->stats.rx_dropped++; | ||
1248 | priv->stats.rx_length_errors++; | ||
1249 | goto done; | ||
1250 | } | ||
1251 | skb_reset_mac_header(pskb); | ||
1252 | new_len = curr_pdu->pdu_offset; | ||
1253 | if (do_debug_data) | ||
1254 | ctcm_pr_debug("ctcmpc: %s() new_len: %04x \n", | ||
1255 | __FUNCTION__, new_len); | ||
1256 | if ((new_len == 0) || (new_len > pskb->len)) { | ||
1257 | /* should never happen */ | ||
1258 | /* pskb len must be hosed...bail out */ | ||
1259 | printk(KERN_INFO | ||
1260 | "ctcmpc: %s(): invalid pdu" | ||
1261 | " offset of %04x - data may be" | ||
1262 | "lost\n", __FUNCTION__, new_len); | ||
1263 | goto done; | ||
1264 | } | ||
1265 | skb = __dev_alloc_skb(new_len+4, GFP_ATOMIC); | ||
1266 | |||
1267 | if (!skb) { | ||
1268 | printk(KERN_INFO | ||
1269 | "ctcm: %s Out of memory in " | ||
1270 | "%s()- request-len:%04x \n", | ||
1271 | dev->name, | ||
1272 | __FUNCTION__, | ||
1273 | new_len+4); | ||
1274 | priv->stats.rx_dropped++; | ||
1275 | fsm_event(grp->fsm, | ||
1276 | MPCG_EVENT_INOP, dev); | ||
1277 | goto done; | ||
1278 | } | ||
1279 | |||
1280 | memcpy(skb_put(skb, new_len), | ||
1281 | pskb->data, new_len); | ||
1282 | |||
1283 | skb_reset_mac_header(skb); | ||
1284 | skb->dev = pskb->dev; | ||
1285 | skb->protocol = pskb->protocol; | ||
1286 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1287 | *((__u32 *) skb_push(skb, 4)) = ch->pdu_seq; | ||
1288 | ch->pdu_seq++; | ||
1289 | |||
1290 | if (do_debug_data) | ||
1291 | ctcm_pr_debug("%s: ToDCM_pdu_seq= %08x\n", | ||
1292 | __FUNCTION__, ch->pdu_seq); | ||
1293 | |||
1294 | ctcm_pr_debug("ctcm: %s() skb:%0lx " | ||
1295 | "skb len: %d \n", __FUNCTION__, | ||
1296 | (unsigned long)skb, skb->len); | ||
1297 | if (do_debug_data) { | ||
1298 | ctcm_pr_debug("ctcmpc: %s() up to 32 bytes" | ||
1299 | " of pdu_data sent\n", | ||
1300 | __FUNCTION__); | ||
1301 | ctcmpc_dump32((char *)skb->data, skb->len); | ||
1302 | } | ||
1303 | |||
1304 | skblen = skb->len; | ||
1305 | sendrc = netif_rx(skb); | ||
1306 | priv->stats.rx_packets++; | ||
1307 | priv->stats.rx_bytes += skblen; | ||
1308 | skb_pull(pskb, new_len); /* point to next PDU */ | ||
1309 | } | ||
1310 | } else { | ||
1311 | mpcginfo = (struct mpcg_info *) | ||
1312 | kmalloc(sizeof(struct mpcg_info), gfp_type()); | ||
1313 | if (mpcginfo == NULL) | ||
1314 | goto done; | ||
1315 | |||
1316 | mpcginfo->ch = ch; | ||
1317 | mpcginfo->th = header; | ||
1318 | mpcginfo->skb = pskb; | ||
1319 | ctcm_pr_debug("ctcmpc: %s() Not PDU - may be control pkt\n", | ||
1320 | __FUNCTION__); | ||
1321 | /* it's a sweep? */ | ||
1322 | sweep = (struct th_sweep *)pskb->data; | ||
1323 | mpcginfo->sweep = sweep; | ||
1324 | if (header->th_ch_flag == TH_SWEEP_REQ) | ||
1325 | mpc_rcvd_sweep_req(mpcginfo); | ||
1326 | else if (header->th_ch_flag == TH_SWEEP_RESP) | ||
1327 | mpc_rcvd_sweep_resp(mpcginfo); | ||
1328 | else if (header->th_blk_flag == TH_DATA_IS_XID) { | ||
1329 | struct xid2 *thisxid = (struct xid2 *)pskb->data; | ||
1330 | skb_pull(pskb, XID2_LENGTH); | ||
1331 | mpcginfo->xid = thisxid; | ||
1332 | fsm_event(grp->fsm, MPCG_EVENT_XID2, mpcginfo); | ||
1333 | } else if (header->th_blk_flag == TH_DISCONTACT) | ||
1334 | fsm_event(grp->fsm, MPCG_EVENT_DISCONC, mpcginfo); | ||
1335 | else if (header->th_seq_num != 0) { | ||
1336 | printk(KERN_INFO "%s unexpected packet" | ||
1337 | " expected control pkt\n", dev->name); | ||
1338 | priv->stats.rx_dropped++; | ||
1339 | /* mpcginfo only used for non-data transfers */ | ||
1340 | kfree(mpcginfo); | ||
1341 | if (do_debug_data) | ||
1342 | ctcmpc_dump_skb(pskb, -8); | ||
1343 | } | ||
1344 | } | ||
1345 | done: | ||
1346 | |||
1347 | dev_kfree_skb_any(pskb); | ||
1348 | if (sendrc == NET_RX_DROP) { | ||
1349 | printk(KERN_WARNING "%s %s() NETWORK BACKLOG EXCEEDED" | ||
1350 | " - PACKET DROPPED\n", dev->name, __FUNCTION__); | ||
1351 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
1352 | } | ||
1353 | |||
1354 | if (do_debug) | ||
1355 | ctcm_pr_debug("ctcmpc exit : %s %s(): ch=0x%p id=%s\n", | ||
1356 | dev->name, __FUNCTION__, ch, ch->id); | ||
1357 | } | ||
1358 | |||
1359 | /** | ||
1360 | * tasklet helper for mpc's skb unpacking. | ||
1361 | * | ||
1362 | * ch The channel to work on. | ||
1363 | * Allow flow control back pressure to occur here. | ||
1364 | * Throttling back channel can result in excessive | ||
1365 | * channel inactivity and system deact of channel | ||
1366 | */ | ||
1367 | void ctcmpc_bh(unsigned long thischan) | ||
1368 | { | ||
1369 | struct channel *ch = (struct channel *)thischan; | ||
1370 | struct sk_buff *skb; | ||
1371 | struct net_device *dev = ch->netdev; | ||
1372 | struct ctcm_priv *priv = dev->priv; | ||
1373 | struct mpc_group *grp = priv->mpcg; | ||
1374 | |||
1375 | if (do_debug) | ||
1376 | ctcm_pr_debug("%s cp:%i enter: %s() %s\n", | ||
1377 | dev->name, smp_processor_id(), __FUNCTION__, ch->id); | ||
1378 | /* caller has requested driver to throttle back */ | ||
1379 | while ((fsm_getstate(grp->fsm) != MPCG_STATE_FLOWC) && | ||
1380 | (skb = skb_dequeue(&ch->io_queue))) { | ||
1381 | ctcmpc_unpack_skb(ch, skb); | ||
1382 | if (grp->out_of_sequence > 20) { | ||
1383 | /* assume data loss has occurred if */ | ||
1384 | /* missing seq_num for extended */ | ||
1385 | /* period of time */ | ||
1386 | grp->out_of_sequence = 0; | ||
1387 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
1388 | break; | ||
1389 | } | ||
1390 | if (skb == skb_peek(&ch->io_queue)) | ||
1391 | break; | ||
1392 | } | ||
1393 | if (do_debug) | ||
1394 | ctcm_pr_debug("ctcmpc exit : %s %s(): ch=0x%p id=%s\n", | ||
1395 | dev->name, __FUNCTION__, ch, ch->id); | ||
1396 | return; | ||
1397 | } | ||
1398 | |||
1399 | /* | ||
1400 | * MPC Group Initializations | ||
1401 | */ | ||
1402 | struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv) | ||
1403 | { | ||
1404 | struct mpc_group *grp; | ||
1405 | |||
1406 | CTCM_DBF_TEXT(MPC_SETUP, 3, __FUNCTION__); | ||
1407 | |||
1408 | grp = kzalloc(sizeof(struct mpc_group), GFP_KERNEL); | ||
1409 | if (grp == NULL) | ||
1410 | return NULL; | ||
1411 | |||
1412 | grp->fsm = | ||
1413 | init_fsm("mpcg", mpcg_state_names, mpcg_event_names, | ||
1414 | MPCG_NR_STATES, MPCG_NR_EVENTS, mpcg_fsm, | ||
1415 | mpcg_fsm_len, GFP_KERNEL); | ||
1416 | if (grp->fsm == NULL) { | ||
1417 | kfree(grp); | ||
1418 | return NULL; | ||
1419 | } | ||
1420 | |||
1421 | fsm_newstate(grp->fsm, MPCG_STATE_RESET); | ||
1422 | fsm_settimer(grp->fsm, &grp->timer); | ||
1423 | |||
1424 | grp->xid_skb = | ||
1425 | __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, GFP_ATOMIC | GFP_DMA); | ||
1426 | if (grp->xid_skb == NULL) { | ||
1427 | printk(KERN_INFO "Couldn't alloc MPCgroup xid_skb\n"); | ||
1428 | kfree_fsm(grp->fsm); | ||
1429 | kfree(grp); | ||
1430 | return NULL; | ||
1431 | } | ||
1432 | /* base xid for all channels in group */ | ||
1433 | grp->xid_skb_data = grp->xid_skb->data; | ||
1434 | grp->xid_th = (struct th_header *)grp->xid_skb->data; | ||
1435 | memcpy(skb_put(grp->xid_skb, TH_HEADER_LENGTH), | ||
1436 | &thnorm, TH_HEADER_LENGTH); | ||
1437 | |||
1438 | grp->xid = (struct xid2 *) skb_tail_pointer(grp->xid_skb); | ||
1439 | memcpy(skb_put(grp->xid_skb, XID2_LENGTH), &init_xid, XID2_LENGTH); | ||
1440 | grp->xid->xid2_adj_id = jiffies | 0xfff00000; | ||
1441 | grp->xid->xid2_sender_id = jiffies; | ||
1442 | |||
1443 | grp->xid_id = skb_tail_pointer(grp->xid_skb); | ||
1444 | memcpy(skb_put(grp->xid_skb, 4), "VTAM", 4); | ||
1445 | |||
1446 | grp->rcvd_xid_skb = | ||
1447 | __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, GFP_ATOMIC|GFP_DMA); | ||
1448 | if (grp->rcvd_xid_skb == NULL) { | ||
1449 | printk(KERN_INFO "Couldn't alloc MPCgroup rcvd_xid_skb\n"); | ||
1450 | kfree_fsm(grp->fsm); | ||
1451 | dev_kfree_skb(grp->xid_skb); | ||
1452 | kfree(grp); | ||
1453 | return NULL; | ||
1454 | } | ||
1455 | grp->rcvd_xid_data = grp->rcvd_xid_skb->data; | ||
1456 | grp->rcvd_xid_th = (struct th_header *)grp->rcvd_xid_skb->data; | ||
1457 | memcpy(skb_put(grp->rcvd_xid_skb, TH_HEADER_LENGTH), | ||
1458 | &thnorm, TH_HEADER_LENGTH); | ||
1459 | grp->saved_xid2 = NULL; | ||
1460 | priv->xid = grp->xid; | ||
1461 | priv->mpcg = grp; | ||
1462 | return grp; | ||
1463 | } | ||
1464 | |||
1465 | /* | ||
1466 | * The MPC Group Station FSM | ||
1467 | */ | ||
1468 | |||
1469 | /* | ||
1470 | * MPC Group Station FSM actions | ||
1471 | * CTCM_PROTO_MPC only | ||
1472 | */ | ||
1473 | |||
1474 | /** | ||
1475 | * NOP action for statemachines | ||
1476 | */ | ||
1477 | static void mpc_action_nop(fsm_instance *fi, int event, void *arg) | ||
1478 | { | ||
1479 | } | ||
1480 | |||
1481 | /* | ||
1482 | * invoked when the device transitions to dev_stopped | ||
1483 | * MPC will stop each individual channel if a single XID failure | ||
1484 | * occurs, or will intitiate all channels be stopped if a GROUP | ||
1485 | * level failure occurs. | ||
1486 | */ | ||
1487 | static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) | ||
1488 | { | ||
1489 | struct net_device *dev = arg; | ||
1490 | struct ctcm_priv *priv; | ||
1491 | struct mpc_group *grp; | ||
1492 | int rc = 0; | ||
1493 | struct channel *wch, *rch; | ||
1494 | |||
1495 | if (dev == NULL) { | ||
1496 | printk(KERN_INFO "%s() dev=NULL\n", __FUNCTION__); | ||
1497 | return; | ||
1498 | } | ||
1499 | |||
1500 | ctcm_pr_debug("ctcmpc enter: %s %s()\n", dev->name, __FUNCTION__); | ||
1501 | |||
1502 | priv = dev->priv; | ||
1503 | grp = priv->mpcg; | ||
1504 | grp->flow_off_called = 0; | ||
1505 | |||
1506 | fsm_deltimer(&grp->timer); | ||
1507 | |||
1508 | if (grp->channels_terminating) | ||
1509 | goto done; | ||
1510 | |||
1511 | grp->channels_terminating = 1; | ||
1512 | |||
1513 | grp->saved_state = fsm_getstate(grp->fsm); | ||
1514 | fsm_newstate(grp->fsm, MPCG_STATE_INOP); | ||
1515 | if (grp->saved_state > MPCG_STATE_XID7INITF) | ||
1516 | printk(KERN_NOTICE "%s:MPC GROUP INOPERATIVE\n", dev->name); | ||
1517 | if ((grp->saved_state != MPCG_STATE_RESET) || | ||
1518 | /* dealloc_channel has been called */ | ||
1519 | ((grp->saved_state == MPCG_STATE_RESET) && | ||
1520 | (grp->port_persist == 0))) | ||
1521 | fsm_deltimer(&priv->restart_timer); | ||
1522 | |||
1523 | wch = priv->channel[WRITE]; | ||
1524 | rch = priv->channel[READ]; | ||
1525 | |||
1526 | switch (grp->saved_state) { | ||
1527 | case MPCG_STATE_RESET: | ||
1528 | case MPCG_STATE_INOP: | ||
1529 | case MPCG_STATE_XID2INITW: | ||
1530 | case MPCG_STATE_XID0IOWAIT: | ||
1531 | case MPCG_STATE_XID2INITX: | ||
1532 | case MPCG_STATE_XID7INITW: | ||
1533 | case MPCG_STATE_XID7INITX: | ||
1534 | case MPCG_STATE_XID0IOWAIX: | ||
1535 | case MPCG_STATE_XID7INITI: | ||
1536 | case MPCG_STATE_XID7INITZ: | ||
1537 | case MPCG_STATE_XID7INITF: | ||
1538 | break; | ||
1539 | case MPCG_STATE_FLOWC: | ||
1540 | case MPCG_STATE_READY: | ||
1541 | default: | ||
1542 | tasklet_hi_schedule(&wch->ch_disc_tasklet); | ||
1543 | } | ||
1544 | |||
1545 | grp->xid2_tgnum = 0; | ||
1546 | grp->group_max_buflen = 0; /*min of all received */ | ||
1547 | grp->outstanding_xid2 = 0; | ||
1548 | grp->outstanding_xid7 = 0; | ||
1549 | grp->outstanding_xid7_p2 = 0; | ||
1550 | grp->saved_xid2 = NULL; | ||
1551 | grp->xidnogood = 0; | ||
1552 | grp->changed_side = 0; | ||
1553 | |||
1554 | grp->rcvd_xid_skb->data = grp->rcvd_xid_data; | ||
1555 | skb_reset_tail_pointer(grp->rcvd_xid_skb); | ||
1556 | grp->rcvd_xid_skb->len = 0; | ||
1557 | grp->rcvd_xid_th = (struct th_header *)grp->rcvd_xid_skb->data; | ||
1558 | memcpy(skb_put(grp->rcvd_xid_skb, TH_HEADER_LENGTH), &thnorm, | ||
1559 | TH_HEADER_LENGTH); | ||
1560 | |||
1561 | if (grp->send_qllc_disc == 1) { | ||
1562 | grp->send_qllc_disc = 0; | ||
1563 | rc = mpc_send_qllc_discontact(dev); | ||
1564 | } | ||
1565 | |||
1566 | /* DO NOT issue DEV_EVENT_STOP directly out of this code */ | ||
1567 | /* This can result in INOP of VTAM PU due to halting of */ | ||
1568 | /* outstanding IO which causes a sense to be returned */ | ||
1569 | /* Only about 3 senses are allowed and then IOS/VTAM will*/ | ||
1570 | /* ebcome unreachable without manual intervention */ | ||
1571 | if ((grp->port_persist == 1) || (grp->alloc_called)) { | ||
1572 | grp->alloc_called = 0; | ||
1573 | fsm_deltimer(&priv->restart_timer); | ||
1574 | fsm_addtimer(&priv->restart_timer, | ||
1575 | 500, | ||
1576 | DEV_EVENT_RESTART, | ||
1577 | dev); | ||
1578 | fsm_newstate(grp->fsm, MPCG_STATE_RESET); | ||
1579 | if (grp->saved_state > MPCG_STATE_XID7INITF) | ||
1580 | printk(KERN_NOTICE "%s:MPC GROUP RECOVERY SCHEDULED\n", | ||
1581 | dev->name); | ||
1582 | } else { | ||
1583 | fsm_deltimer(&priv->restart_timer); | ||
1584 | fsm_addtimer(&priv->restart_timer, 500, DEV_EVENT_STOP, dev); | ||
1585 | fsm_newstate(grp->fsm, MPCG_STATE_RESET); | ||
1586 | printk(KERN_NOTICE "%s:MPC GROUP RECOVERY NOT ATTEMPTED\n", | ||
1587 | dev->name); | ||
1588 | } | ||
1589 | |||
1590 | done: | ||
1591 | ctcm_pr_debug("ctcmpc exit:%s %s()\n", dev->name, __FUNCTION__); | ||
1592 | return; | ||
1593 | } | ||
1594 | |||
1595 | /** | ||
1596 | * Handle mpc group action timeout. | ||
1597 | * MPC Group Station FSM action | ||
1598 | * CTCM_PROTO_MPC only | ||
1599 | * | ||
1600 | * fi An instance of an mpc_group fsm. | ||
1601 | * event The event, just happened. | ||
1602 | * arg Generic pointer, casted from net_device * upon call. | ||
1603 | */ | ||
1604 | static void mpc_action_timeout(fsm_instance *fi, int event, void *arg) | ||
1605 | { | ||
1606 | struct net_device *dev = arg; | ||
1607 | struct ctcm_priv *priv; | ||
1608 | struct mpc_group *grp; | ||
1609 | struct channel *wch; | ||
1610 | struct channel *rch; | ||
1611 | |||
1612 | CTCM_DBF_TEXT(MPC_TRACE, 6, __FUNCTION__); | ||
1613 | |||
1614 | if (dev == NULL) { | ||
1615 | CTCM_DBF_TEXT_(MPC_ERROR, 4, "%s: dev=NULL\n", __FUNCTION__); | ||
1616 | return; | ||
1617 | } | ||
1618 | |||
1619 | priv = dev->priv; | ||
1620 | grp = priv->mpcg; | ||
1621 | wch = priv->channel[WRITE]; | ||
1622 | rch = priv->channel[READ]; | ||
1623 | |||
1624 | switch (fsm_getstate(grp->fsm)) { | ||
1625 | case MPCG_STATE_XID2INITW: | ||
1626 | /* Unless there is outstanding IO on the */ | ||
1627 | /* channel just return and wait for ATTN */ | ||
1628 | /* interrupt to begin XID negotiations */ | ||
1629 | if ((fsm_getstate(rch->fsm) == CH_XID0_PENDING) && | ||
1630 | (fsm_getstate(wch->fsm) == CH_XID0_PENDING)) | ||
1631 | break; | ||
1632 | default: | ||
1633 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
1634 | } | ||
1635 | |||
1636 | CTCM_DBF_TEXT_(MPC_TRACE, 6, "%s: dev=%s exit", | ||
1637 | __FUNCTION__, dev->name); | ||
1638 | return; | ||
1639 | } | ||
1640 | |||
1641 | /* | ||
1642 | * MPC Group Station FSM action | ||
1643 | * CTCM_PROTO_MPC only | ||
1644 | */ | ||
1645 | void mpc_action_discontact(fsm_instance *fi, int event, void *arg) | ||
1646 | { | ||
1647 | struct mpcg_info *mpcginfo = arg; | ||
1648 | struct channel *ch = mpcginfo->ch; | ||
1649 | struct net_device *dev = ch->netdev; | ||
1650 | struct ctcm_priv *priv = dev->priv; | ||
1651 | struct mpc_group *grp = priv->mpcg; | ||
1652 | |||
1653 | if (ch == NULL) { | ||
1654 | printk(KERN_INFO "%s() ch=NULL\n", __FUNCTION__); | ||
1655 | return; | ||
1656 | } | ||
1657 | if (ch->netdev == NULL) { | ||
1658 | printk(KERN_INFO "%s() dev=NULL\n", __FUNCTION__); | ||
1659 | return; | ||
1660 | } | ||
1661 | |||
1662 | ctcm_pr_debug("ctcmpc enter: %s %s()\n", dev->name, __FUNCTION__); | ||
1663 | |||
1664 | grp->send_qllc_disc = 1; | ||
1665 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
1666 | |||
1667 | ctcm_pr_debug("ctcmpc exit: %s %s()\n", dev->name, __FUNCTION__); | ||
1668 | return; | ||
1669 | } | ||
1670 | |||
1671 | /* | ||
1672 | * MPC Group Station - not part of FSM | ||
1673 | * CTCM_PROTO_MPC only | ||
1674 | * called from add_channel in ctcm_main.c | ||
1675 | */ | ||
1676 | void mpc_action_send_discontact(unsigned long thischan) | ||
1677 | { | ||
1678 | struct channel *ch; | ||
1679 | struct net_device *dev; | ||
1680 | struct ctcm_priv *priv; | ||
1681 | struct mpc_group *grp; | ||
1682 | int rc = 0; | ||
1683 | unsigned long saveflags; | ||
1684 | |||
1685 | ch = (struct channel *)thischan; | ||
1686 | dev = ch->netdev; | ||
1687 | priv = dev->priv; | ||
1688 | grp = priv->mpcg; | ||
1689 | |||
1690 | ctcm_pr_info("ctcmpc: %s cp:%i enter: %s() GrpState:%s ChState:%s\n", | ||
1691 | dev->name, | ||
1692 | smp_processor_id(), | ||
1693 | __FUNCTION__, | ||
1694 | fsm_getstate_str(grp->fsm), | ||
1695 | fsm_getstate_str(ch->fsm)); | ||
1696 | saveflags = 0; /* avoids compiler warning with | ||
1697 | spin_unlock_irqrestore */ | ||
1698 | |||
1699 | spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); | ||
1700 | rc = ccw_device_start(ch->cdev, &ch->ccw[15], | ||
1701 | (unsigned long)ch, 0xff, 0); | ||
1702 | spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); | ||
1703 | |||
1704 | if (rc != 0) { | ||
1705 | ctcm_pr_info("ctcmpc: %s() ch:%s IO failed \n", | ||
1706 | __FUNCTION__, | ||
1707 | ch->id); | ||
1708 | ctcm_ccw_check_rc(ch, rc, "send discontact"); | ||
1709 | /* Not checking return code value here */ | ||
1710 | /* Making best effort to notify partner*/ | ||
1711 | /* that MPC Group is going down */ | ||
1712 | } | ||
1713 | |||
1714 | ctcm_pr_debug("ctcmpc exit: %s %s()\n", dev->name, __FUNCTION__); | ||
1715 | return; | ||
1716 | } | ||
1717 | |||
1718 | |||
1719 | /* | ||
1720 | * helper function of mpc FSM | ||
1721 | * CTCM_PROTO_MPC only | ||
1722 | * mpc_action_rcvd_xid7 | ||
1723 | */ | ||
1724 | static int mpc_validate_xid(struct mpcg_info *mpcginfo) | ||
1725 | { | ||
1726 | struct channel *ch = mpcginfo->ch; | ||
1727 | struct net_device *dev = ch->netdev; | ||
1728 | struct ctcm_priv *priv = dev->priv; | ||
1729 | struct mpc_group *grp = priv->mpcg; | ||
1730 | struct xid2 *xid = mpcginfo->xid; | ||
1731 | int failed = 0; | ||
1732 | int rc = 0; | ||
1733 | __u64 our_id, their_id = 0; | ||
1734 | int len; | ||
1735 | |||
1736 | len = TH_HEADER_LENGTH + PDU_HEADER_LENGTH; | ||
1737 | |||
1738 | ctcm_pr_debug("ctcmpc enter: %s()\n", __FUNCTION__); | ||
1739 | |||
1740 | if (mpcginfo->xid == NULL) { | ||
1741 | printk(KERN_INFO "%s() xid=NULL\n", __FUNCTION__); | ||
1742 | rc = 1; | ||
1743 | goto done; | ||
1744 | } | ||
1745 | |||
1746 | ctcm_pr_debug("ctcmpc : %s xid received()\n", __FUNCTION__); | ||
1747 | ctcmpc_dumpit((char *)mpcginfo->xid, XID2_LENGTH); | ||
1748 | |||
1749 | /*the received direction should be the opposite of ours */ | ||
1750 | if (((CHANNEL_DIRECTION(ch->flags) == READ) ? XID2_WRITE_SIDE : | ||
1751 | XID2_READ_SIDE) != xid->xid2_dlc_type) { | ||
1752 | failed = 1; | ||
1753 | printk(KERN_INFO "ctcmpc:%s() XID REJECTED - READ-WRITE CH " | ||
1754 | "Pairing Invalid \n", __FUNCTION__); | ||
1755 | } | ||
1756 | |||
1757 | if (xid->xid2_dlc_type == XID2_READ_SIDE) { | ||
1758 | ctcm_pr_debug("ctcmpc: %s(): grpmaxbuf:%d xid2buflen:%d\n", | ||
1759 | __FUNCTION__, grp->group_max_buflen, | ||
1760 | xid->xid2_buf_len); | ||
1761 | |||
1762 | if (grp->group_max_buflen == 0 || | ||
1763 | grp->group_max_buflen > xid->xid2_buf_len - len) | ||
1764 | grp->group_max_buflen = xid->xid2_buf_len - len; | ||
1765 | } | ||
1766 | |||
1767 | |||
1768 | if (grp->saved_xid2 == NULL) { | ||
1769 | grp->saved_xid2 = | ||
1770 | (struct xid2 *)skb_tail_pointer(grp->rcvd_xid_skb); | ||
1771 | |||
1772 | memcpy(skb_put(grp->rcvd_xid_skb, | ||
1773 | XID2_LENGTH), xid, XID2_LENGTH); | ||
1774 | grp->rcvd_xid_skb->data = grp->rcvd_xid_data; | ||
1775 | |||
1776 | skb_reset_tail_pointer(grp->rcvd_xid_skb); | ||
1777 | grp->rcvd_xid_skb->len = 0; | ||
1778 | |||
1779 | /* convert two 32 bit numbers into 1 64 bit for id compare */ | ||
1780 | our_id = (__u64)priv->xid->xid2_adj_id; | ||
1781 | our_id = our_id << 32; | ||
1782 | our_id = our_id + priv->xid->xid2_sender_id; | ||
1783 | their_id = (__u64)xid->xid2_adj_id; | ||
1784 | their_id = their_id << 32; | ||
1785 | their_id = their_id + xid->xid2_sender_id; | ||
1786 | /* lower id assume the xside role */ | ||
1787 | if (our_id < their_id) { | ||
1788 | grp->roll = XSIDE; | ||
1789 | ctcm_pr_debug("ctcmpc :%s() WE HAVE LOW ID-" | ||
1790 | "TAKE XSIDE\n", __FUNCTION__); | ||
1791 | } else { | ||
1792 | grp->roll = YSIDE; | ||
1793 | ctcm_pr_debug("ctcmpc :%s() WE HAVE HIGH ID-" | ||
1794 | "TAKE YSIDE\n", __FUNCTION__); | ||
1795 | } | ||
1796 | |||
1797 | } else { | ||
1798 | if (xid->xid2_flag4 != grp->saved_xid2->xid2_flag4) { | ||
1799 | failed = 1; | ||
1800 | printk(KERN_INFO "%s XID REJECTED - XID Flag Byte4\n", | ||
1801 | __FUNCTION__); | ||
1802 | } | ||
1803 | if (xid->xid2_flag2 == 0x40) { | ||
1804 | failed = 1; | ||
1805 | printk(KERN_INFO "%s XID REJECTED - XID NOGOOD\n", | ||
1806 | __FUNCTION__); | ||
1807 | } | ||
1808 | if (xid->xid2_adj_id != grp->saved_xid2->xid2_adj_id) { | ||
1809 | failed = 1; | ||
1810 | printk(KERN_INFO "%s XID REJECTED - " | ||
1811 | "Adjacent Station ID Mismatch\n", | ||
1812 | __FUNCTION__); | ||
1813 | } | ||
1814 | if (xid->xid2_sender_id != grp->saved_xid2->xid2_sender_id) { | ||
1815 | failed = 1; | ||
1816 | printk(KERN_INFO "%s XID REJECTED - " | ||
1817 | "Sender Address Mismatch\n", __FUNCTION__); | ||
1818 | |||
1819 | } | ||
1820 | } | ||
1821 | |||
1822 | if (failed) { | ||
1823 | ctcm_pr_info("ctcmpc : %s() failed\n", __FUNCTION__); | ||
1824 | priv->xid->xid2_flag2 = 0x40; | ||
1825 | grp->saved_xid2->xid2_flag2 = 0x40; | ||
1826 | rc = 1; | ||
1827 | } | ||
1828 | |||
1829 | done: | ||
1830 | |||
1831 | ctcm_pr_debug("ctcmpc exit: %s()\n", __FUNCTION__); | ||
1832 | return rc; | ||
1833 | } | ||
1834 | |||
1835 | /* | ||
1836 | * MPC Group Station FSM action | ||
1837 | * CTCM_PROTO_MPC only | ||
1838 | */ | ||
1839 | static void mpc_action_side_xid(fsm_instance *fsm, void *arg, int side) | ||
1840 | { | ||
1841 | struct channel *ch = arg; | ||
1842 | struct ctcm_priv *priv; | ||
1843 | struct mpc_group *grp = NULL; | ||
1844 | struct net_device *dev = NULL; | ||
1845 | int rc = 0; | ||
1846 | int gotlock = 0; | ||
1847 | unsigned long saveflags = 0; /* avoids compiler warning with | ||
1848 | spin_unlock_irqrestore */ | ||
1849 | |||
1850 | if (ch == NULL) { | ||
1851 | printk(KERN_INFO "%s ch=NULL\n", __FUNCTION__); | ||
1852 | goto done; | ||
1853 | } | ||
1854 | |||
1855 | if (do_debug) | ||
1856 | ctcm_pr_debug("ctcmpc enter: %s(): cp=%i ch=0x%p id=%s\n", | ||
1857 | __FUNCTION__, smp_processor_id(), ch, ch->id); | ||
1858 | |||
1859 | dev = ch->netdev; | ||
1860 | if (dev == NULL) { | ||
1861 | printk(KERN_INFO "%s dev=NULL\n", __FUNCTION__); | ||
1862 | goto done; | ||
1863 | } | ||
1864 | |||
1865 | priv = dev->priv; | ||
1866 | if (priv == NULL) { | ||
1867 | printk(KERN_INFO "%s priv=NULL\n", __FUNCTION__); | ||
1868 | goto done; | ||
1869 | } | ||
1870 | |||
1871 | grp = priv->mpcg; | ||
1872 | if (grp == NULL) { | ||
1873 | printk(KERN_INFO "%s grp=NULL\n", __FUNCTION__); | ||
1874 | goto done; | ||
1875 | } | ||
1876 | |||
1877 | if (ctcm_checkalloc_buffer(ch)) | ||
1878 | goto done; | ||
1879 | |||
1880 | /* skb data-buffer referencing: */ | ||
1881 | |||
1882 | ch->trans_skb->data = ch->trans_skb_data; | ||
1883 | skb_reset_tail_pointer(ch->trans_skb); | ||
1884 | ch->trans_skb->len = 0; | ||
1885 | /* result of the previous 3 statements is NOT always | ||
1886 | * already set after ctcm_checkalloc_buffer | ||
1887 | * because of possible reuse of the trans_skb | ||
1888 | */ | ||
1889 | memset(ch->trans_skb->data, 0, 16); | ||
1890 | ch->rcvd_xid_th = (struct th_header *)ch->trans_skb_data; | ||
1891 | /* check is main purpose here: */ | ||
1892 | skb_put(ch->trans_skb, TH_HEADER_LENGTH); | ||
1893 | ch->rcvd_xid = (struct xid2 *)skb_tail_pointer(ch->trans_skb); | ||
1894 | /* check is main purpose here: */ | ||
1895 | skb_put(ch->trans_skb, XID2_LENGTH); | ||
1896 | ch->rcvd_xid_id = skb_tail_pointer(ch->trans_skb); | ||
1897 | /* cleanup back to startpoint */ | ||
1898 | ch->trans_skb->data = ch->trans_skb_data; | ||
1899 | skb_reset_tail_pointer(ch->trans_skb); | ||
1900 | ch->trans_skb->len = 0; | ||
1901 | |||
1902 | /* non-checking rewrite of above skb data-buffer referencing: */ | ||
1903 | /* | ||
1904 | memset(ch->trans_skb->data, 0, 16); | ||
1905 | ch->rcvd_xid_th = (struct th_header *)ch->trans_skb_data; | ||
1906 | ch->rcvd_xid = (struct xid2 *)(ch->trans_skb_data + TH_HEADER_LENGTH); | ||
1907 | ch->rcvd_xid_id = ch->trans_skb_data + TH_HEADER_LENGTH + XID2_LENGTH; | ||
1908 | */ | ||
1909 | |||
1910 | ch->ccw[8].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1911 | ch->ccw[8].count = 0; | ||
1912 | ch->ccw[8].cda = 0x00; | ||
1913 | |||
1914 | if (side == XSIDE) { | ||
1915 | /* mpc_action_xside_xid */ | ||
1916 | if (ch->xid_th == NULL) { | ||
1917 | printk(KERN_INFO "%s ch->xid_th=NULL\n", __FUNCTION__); | ||
1918 | goto done; | ||
1919 | } | ||
1920 | ch->ccw[9].cmd_code = CCW_CMD_WRITE; | ||
1921 | ch->ccw[9].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1922 | ch->ccw[9].count = TH_HEADER_LENGTH; | ||
1923 | ch->ccw[9].cda = virt_to_phys(ch->xid_th); | ||
1924 | |||
1925 | if (ch->xid == NULL) { | ||
1926 | printk(KERN_INFO "%s ch->xid=NULL\n", __FUNCTION__); | ||
1927 | goto done; | ||
1928 | } | ||
1929 | |||
1930 | ch->ccw[10].cmd_code = CCW_CMD_WRITE; | ||
1931 | ch->ccw[10].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1932 | ch->ccw[10].count = XID2_LENGTH; | ||
1933 | ch->ccw[10].cda = virt_to_phys(ch->xid); | ||
1934 | |||
1935 | ch->ccw[11].cmd_code = CCW_CMD_READ; | ||
1936 | ch->ccw[11].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1937 | ch->ccw[11].count = TH_HEADER_LENGTH; | ||
1938 | ch->ccw[11].cda = virt_to_phys(ch->rcvd_xid_th); | ||
1939 | |||
1940 | ch->ccw[12].cmd_code = CCW_CMD_READ; | ||
1941 | ch->ccw[12].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1942 | ch->ccw[12].count = XID2_LENGTH; | ||
1943 | ch->ccw[12].cda = virt_to_phys(ch->rcvd_xid); | ||
1944 | |||
1945 | ch->ccw[13].cmd_code = CCW_CMD_READ; | ||
1946 | ch->ccw[13].cda = virt_to_phys(ch->rcvd_xid_id); | ||
1947 | |||
1948 | } else { /* side == YSIDE : mpc_action_yside_xid */ | ||
1949 | ch->ccw[9].cmd_code = CCW_CMD_READ; | ||
1950 | ch->ccw[9].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1951 | ch->ccw[9].count = TH_HEADER_LENGTH; | ||
1952 | ch->ccw[9].cda = virt_to_phys(ch->rcvd_xid_th); | ||
1953 | |||
1954 | ch->ccw[10].cmd_code = CCW_CMD_READ; | ||
1955 | ch->ccw[10].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1956 | ch->ccw[10].count = XID2_LENGTH; | ||
1957 | ch->ccw[10].cda = virt_to_phys(ch->rcvd_xid); | ||
1958 | |||
1959 | if (ch->xid_th == NULL) { | ||
1960 | printk(KERN_INFO "%s ch->xid_th=NULL\n", __FUNCTION__); | ||
1961 | goto done; | ||
1962 | } | ||
1963 | ch->ccw[11].cmd_code = CCW_CMD_WRITE; | ||
1964 | ch->ccw[11].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1965 | ch->ccw[11].count = TH_HEADER_LENGTH; | ||
1966 | ch->ccw[11].cda = virt_to_phys(ch->xid_th); | ||
1967 | |||
1968 | if (ch->xid == NULL) { | ||
1969 | printk(KERN_INFO "%s ch->xid=NULL\n", __FUNCTION__); | ||
1970 | goto done; | ||
1971 | } | ||
1972 | ch->ccw[12].cmd_code = CCW_CMD_WRITE; | ||
1973 | ch->ccw[12].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1974 | ch->ccw[12].count = XID2_LENGTH; | ||
1975 | ch->ccw[12].cda = virt_to_phys(ch->xid); | ||
1976 | |||
1977 | if (ch->xid_id == NULL) { | ||
1978 | printk(KERN_INFO "%s ch->xid_id=NULL\n", __FUNCTION__); | ||
1979 | goto done; | ||
1980 | } | ||
1981 | ch->ccw[13].cmd_code = CCW_CMD_WRITE; | ||
1982 | ch->ccw[13].cda = virt_to_phys(ch->xid_id); | ||
1983 | |||
1984 | } | ||
1985 | ch->ccw[13].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1986 | ch->ccw[13].count = 4; | ||
1987 | |||
1988 | ch->ccw[14].cmd_code = CCW_CMD_NOOP; | ||
1989 | ch->ccw[14].flags = CCW_FLAG_SLI; | ||
1990 | ch->ccw[14].count = 0; | ||
1991 | ch->ccw[14].cda = 0; | ||
1992 | |||
1993 | if (do_debug_ccw) | ||
1994 | ctcmpc_dumpit((char *)&ch->ccw[8], sizeof(struct ccw1) * 7); | ||
1995 | |||
1996 | ctcmpc_dumpit((char *)ch->xid_th, TH_HEADER_LENGTH); | ||
1997 | ctcmpc_dumpit((char *)ch->xid, XID2_LENGTH); | ||
1998 | ctcmpc_dumpit((char *)ch->xid_id, 4); | ||
1999 | if (!in_irq()) { | ||
2000 | /* Such conditional locking is a known problem for | ||
2001 | * sparse because its static undeterministic. | ||
2002 | * Warnings should be ignored here. */ | ||
2003 | spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); | ||
2004 | gotlock = 1; | ||
2005 | } | ||
2006 | |||
2007 | fsm_addtimer(&ch->timer, 5000 , CTC_EVENT_TIMER, ch); | ||
2008 | rc = ccw_device_start(ch->cdev, &ch->ccw[8], | ||
2009 | (unsigned long)ch, 0xff, 0); | ||
2010 | |||
2011 | if (gotlock) /* see remark above about conditional locking */ | ||
2012 | spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); | ||
2013 | |||
2014 | if (rc != 0) { | ||
2015 | ctcm_pr_info("ctcmpc: %s() ch:%s IO failed \n", | ||
2016 | __FUNCTION__, ch->id); | ||
2017 | ctcm_ccw_check_rc(ch, rc, | ||
2018 | (side == XSIDE) ? "x-side XID" : "y-side XID"); | ||
2019 | } | ||
2020 | |||
2021 | done: | ||
2022 | if (do_debug) | ||
2023 | ctcm_pr_debug("ctcmpc exit : %s(): ch=0x%p id=%s\n", | ||
2024 | __FUNCTION__, ch, ch->id); | ||
2025 | return; | ||
2026 | |||
2027 | } | ||
2028 | |||
2029 | /* | ||
2030 | * MPC Group Station FSM action | ||
2031 | * CTCM_PROTO_MPC only | ||
2032 | */ | ||
2033 | static void mpc_action_xside_xid(fsm_instance *fsm, int event, void *arg) | ||
2034 | { | ||
2035 | mpc_action_side_xid(fsm, arg, XSIDE); | ||
2036 | } | ||
2037 | |||
2038 | /* | ||
2039 | * MPC Group Station FSM action | ||
2040 | * CTCM_PROTO_MPC only | ||
2041 | */ | ||
2042 | static void mpc_action_yside_xid(fsm_instance *fsm, int event, void *arg) | ||
2043 | { | ||
2044 | mpc_action_side_xid(fsm, arg, YSIDE); | ||
2045 | } | ||
2046 | |||
2047 | /* | ||
2048 | * MPC Group Station FSM action | ||
2049 | * CTCM_PROTO_MPC only | ||
2050 | */ | ||
2051 | static void mpc_action_doxid0(fsm_instance *fsm, int event, void *arg) | ||
2052 | { | ||
2053 | struct channel *ch = arg; | ||
2054 | struct ctcm_priv *priv; | ||
2055 | struct mpc_group *grp = NULL; | ||
2056 | struct net_device *dev = NULL; | ||
2057 | |||
2058 | if (do_debug) | ||
2059 | ctcm_pr_debug("ctcmpc enter: %s(): cp=%i ch=0x%p id=%s\n", | ||
2060 | __FUNCTION__, smp_processor_id(), ch, ch->id); | ||
2061 | |||
2062 | if (ch == NULL) { | ||
2063 | printk(KERN_WARNING "%s ch=NULL\n", __FUNCTION__); | ||
2064 | goto done; | ||
2065 | } | ||
2066 | |||
2067 | dev = ch->netdev; | ||
2068 | if (dev == NULL) { | ||
2069 | printk(KERN_WARNING "%s dev=NULL\n", __FUNCTION__); | ||
2070 | goto done; | ||
2071 | } | ||
2072 | |||
2073 | priv = dev->priv; | ||
2074 | if (priv == NULL) { | ||
2075 | printk(KERN_WARNING "%s priv=NULL\n", __FUNCTION__); | ||
2076 | goto done; | ||
2077 | } | ||
2078 | |||
2079 | grp = priv->mpcg; | ||
2080 | if (grp == NULL) { | ||
2081 | printk(KERN_WARNING "%s grp=NULL\n", __FUNCTION__); | ||
2082 | goto done; | ||
2083 | } | ||
2084 | |||
2085 | if (ch->xid == NULL) { | ||
2086 | printk(KERN_WARNING "%s ch-xid=NULL\n", __FUNCTION__); | ||
2087 | goto done; | ||
2088 | } | ||
2089 | |||
2090 | fsm_newstate(ch->fsm, CH_XID0_INPROGRESS); | ||
2091 | |||
2092 | ch->xid->xid2_option = XID2_0; | ||
2093 | |||
2094 | switch (fsm_getstate(grp->fsm)) { | ||
2095 | case MPCG_STATE_XID2INITW: | ||
2096 | case MPCG_STATE_XID2INITX: | ||
2097 | ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD; | ||
2098 | break; | ||
2099 | case MPCG_STATE_XID0IOWAIT: | ||
2100 | case MPCG_STATE_XID0IOWAIX: | ||
2101 | ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL; | ||
2102 | break; | ||
2103 | } | ||
2104 | |||
2105 | fsm_event(grp->fsm, MPCG_EVENT_DOIO, ch); | ||
2106 | |||
2107 | done: | ||
2108 | if (do_debug) | ||
2109 | ctcm_pr_debug("ctcmpc exit : %s(): ch=0x%p id=%s\n", | ||
2110 | __FUNCTION__, ch, ch->id); | ||
2111 | return; | ||
2112 | |||
2113 | } | ||
2114 | |||
2115 | /* | ||
2116 | * MPC Group Station FSM action | ||
2117 | * CTCM_PROTO_MPC only | ||
2118 | */ | ||
2119 | static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg) | ||
2120 | { | ||
2121 | struct net_device *dev = arg; | ||
2122 | struct ctcm_priv *priv = NULL; | ||
2123 | struct mpc_group *grp = NULL; | ||
2124 | int direction; | ||
2125 | int rc = 0; | ||
2126 | int send = 0; | ||
2127 | |||
2128 | ctcm_pr_debug("ctcmpc enter: %s() \n", __FUNCTION__); | ||
2129 | |||
2130 | if (dev == NULL) { | ||
2131 | printk(KERN_INFO "%s dev=NULL \n", __FUNCTION__); | ||
2132 | rc = 1; | ||
2133 | goto done; | ||
2134 | } | ||
2135 | |||
2136 | priv = dev->priv; | ||
2137 | if (priv == NULL) { | ||
2138 | printk(KERN_INFO "%s priv=NULL \n", __FUNCTION__); | ||
2139 | rc = 1; | ||
2140 | goto done; | ||
2141 | } | ||
2142 | |||
2143 | grp = priv->mpcg; | ||
2144 | if (grp == NULL) { | ||
2145 | printk(KERN_INFO "%s grp=NULL \n", __FUNCTION__); | ||
2146 | rc = 1; | ||
2147 | goto done; | ||
2148 | } | ||
2149 | |||
2150 | for (direction = READ; direction <= WRITE; direction++) { | ||
2151 | struct channel *ch = priv->channel[direction]; | ||
2152 | struct xid2 *thisxid = ch->xid; | ||
2153 | ch->xid_skb->data = ch->xid_skb_data; | ||
2154 | skb_reset_tail_pointer(ch->xid_skb); | ||
2155 | ch->xid_skb->len = 0; | ||
2156 | thisxid->xid2_option = XID2_7; | ||
2157 | send = 0; | ||
2158 | |||
2159 | /* xid7 phase 1 */ | ||
2160 | if (grp->outstanding_xid7_p2 > 0) { | ||
2161 | if (grp->roll == YSIDE) { | ||
2162 | if (fsm_getstate(ch->fsm) == CH_XID7_PENDING1) { | ||
2163 | fsm_newstate(ch->fsm, CH_XID7_PENDING2); | ||
2164 | ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD; | ||
2165 | memcpy(skb_put(ch->xid_skb, | ||
2166 | TH_HEADER_LENGTH), | ||
2167 | &thdummy, TH_HEADER_LENGTH); | ||
2168 | send = 1; | ||
2169 | } | ||
2170 | } else if (fsm_getstate(ch->fsm) < CH_XID7_PENDING2) { | ||
2171 | fsm_newstate(ch->fsm, CH_XID7_PENDING2); | ||
2172 | ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL; | ||
2173 | memcpy(skb_put(ch->xid_skb, | ||
2174 | TH_HEADER_LENGTH), | ||
2175 | &thnorm, TH_HEADER_LENGTH); | ||
2176 | send = 1; | ||
2177 | } | ||
2178 | } else { | ||
2179 | /* xid7 phase 2 */ | ||
2180 | if (grp->roll == YSIDE) { | ||
2181 | if (fsm_getstate(ch->fsm) < CH_XID7_PENDING4) { | ||
2182 | fsm_newstate(ch->fsm, CH_XID7_PENDING4); | ||
2183 | memcpy(skb_put(ch->xid_skb, | ||
2184 | TH_HEADER_LENGTH), | ||
2185 | &thnorm, TH_HEADER_LENGTH); | ||
2186 | ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL; | ||
2187 | send = 1; | ||
2188 | } | ||
2189 | } else if (fsm_getstate(ch->fsm) == CH_XID7_PENDING3) { | ||
2190 | fsm_newstate(ch->fsm, CH_XID7_PENDING4); | ||
2191 | ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD; | ||
2192 | memcpy(skb_put(ch->xid_skb, TH_HEADER_LENGTH), | ||
2193 | &thdummy, TH_HEADER_LENGTH); | ||
2194 | send = 1; | ||
2195 | } | ||
2196 | } | ||
2197 | |||
2198 | if (send) | ||
2199 | fsm_event(grp->fsm, MPCG_EVENT_DOIO, ch); | ||
2200 | } | ||
2201 | |||
2202 | done: | ||
2203 | |||
2204 | if (rc != 0) | ||
2205 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
2206 | |||
2207 | return; | ||
2208 | } | ||
2209 | |||
2210 | /* | ||
2211 | * MPC Group Station FSM action | ||
2212 | * CTCM_PROTO_MPC only | ||
2213 | */ | ||
2214 | static void mpc_action_rcvd_xid0(fsm_instance *fsm, int event, void *arg) | ||
2215 | { | ||
2216 | |||
2217 | struct mpcg_info *mpcginfo = arg; | ||
2218 | struct channel *ch = mpcginfo->ch; | ||
2219 | struct net_device *dev = ch->netdev; | ||
2220 | struct ctcm_priv *priv; | ||
2221 | struct mpc_group *grp; | ||
2222 | |||
2223 | if (do_debug) | ||
2224 | ctcm_pr_debug("ctcmpc enter: %s(): cp=%i ch=0x%p id=%s\n", | ||
2225 | __FUNCTION__, smp_processor_id(), ch, ch->id); | ||
2226 | |||
2227 | priv = dev->priv; | ||
2228 | grp = priv->mpcg; | ||
2229 | |||
2230 | ctcm_pr_debug("ctcmpc in:%s() %s xid2:%i xid7:%i xidt_p2:%i \n", | ||
2231 | __FUNCTION__, ch->id, | ||
2232 | grp->outstanding_xid2, | ||
2233 | grp->outstanding_xid7, | ||
2234 | grp->outstanding_xid7_p2); | ||
2235 | |||
2236 | if (fsm_getstate(ch->fsm) < CH_XID7_PENDING) | ||
2237 | fsm_newstate(ch->fsm, CH_XID7_PENDING); | ||
2238 | |||
2239 | grp->outstanding_xid2--; | ||
2240 | grp->outstanding_xid7++; | ||
2241 | grp->outstanding_xid7_p2++; | ||
2242 | |||
2243 | /* must change state before validating xid to */ | ||
2244 | /* properly handle interim interrupts received*/ | ||
2245 | switch (fsm_getstate(grp->fsm)) { | ||
2246 | case MPCG_STATE_XID2INITW: | ||
2247 | fsm_newstate(grp->fsm, MPCG_STATE_XID2INITX); | ||
2248 | mpc_validate_xid(mpcginfo); | ||
2249 | break; | ||
2250 | case MPCG_STATE_XID0IOWAIT: | ||
2251 | fsm_newstate(grp->fsm, MPCG_STATE_XID0IOWAIX); | ||
2252 | mpc_validate_xid(mpcginfo); | ||
2253 | break; | ||
2254 | case MPCG_STATE_XID2INITX: | ||
2255 | if (grp->outstanding_xid2 == 0) { | ||
2256 | fsm_newstate(grp->fsm, MPCG_STATE_XID7INITW); | ||
2257 | mpc_validate_xid(mpcginfo); | ||
2258 | fsm_event(grp->fsm, MPCG_EVENT_XID2DONE, dev); | ||
2259 | } | ||
2260 | break; | ||
2261 | case MPCG_STATE_XID0IOWAIX: | ||
2262 | if (grp->outstanding_xid2 == 0) { | ||
2263 | fsm_newstate(grp->fsm, MPCG_STATE_XID7INITI); | ||
2264 | mpc_validate_xid(mpcginfo); | ||
2265 | fsm_event(grp->fsm, MPCG_EVENT_XID2DONE, dev); | ||
2266 | } | ||
2267 | break; | ||
2268 | } | ||
2269 | kfree(mpcginfo); | ||
2270 | |||
2271 | if (do_debug) { | ||
2272 | ctcm_pr_debug("ctcmpc:%s() %s xid2:%i xid7:%i xidt_p2:%i \n", | ||
2273 | __FUNCTION__, ch->id, | ||
2274 | grp->outstanding_xid2, | ||
2275 | grp->outstanding_xid7, | ||
2276 | grp->outstanding_xid7_p2); | ||
2277 | ctcm_pr_debug("ctcmpc:%s() %s grpstate: %s chanstate: %s \n", | ||
2278 | __FUNCTION__, ch->id, | ||
2279 | fsm_getstate_str(grp->fsm), | ||
2280 | fsm_getstate_str(ch->fsm)); | ||
2281 | } | ||
2282 | return; | ||
2283 | |||
2284 | } | ||
2285 | |||
2286 | |||
2287 | /* | ||
2288 | * MPC Group Station FSM action | ||
2289 | * CTCM_PROTO_MPC only | ||
2290 | */ | ||
2291 | static void mpc_action_rcvd_xid7(fsm_instance *fsm, int event, void *arg) | ||
2292 | { | ||
2293 | struct mpcg_info *mpcginfo = arg; | ||
2294 | struct channel *ch = mpcginfo->ch; | ||
2295 | struct net_device *dev = ch->netdev; | ||
2296 | struct ctcm_priv *priv = dev->priv; | ||
2297 | struct mpc_group *grp = priv->mpcg; | ||
2298 | |||
2299 | if (do_debug) { | ||
2300 | ctcm_pr_debug("ctcmpc enter: %s(): cp=%i ch=0x%p id=%s\n", | ||
2301 | __FUNCTION__, smp_processor_id(), ch, ch->id); | ||
2302 | |||
2303 | ctcm_pr_debug("ctcmpc: outstanding_xid7: %i, " | ||
2304 | " outstanding_xid7_p2: %i\n", | ||
2305 | grp->outstanding_xid7, | ||
2306 | grp->outstanding_xid7_p2); | ||
2307 | } | ||
2308 | |||
2309 | grp->outstanding_xid7--; | ||
2310 | ch->xid_skb->data = ch->xid_skb_data; | ||
2311 | skb_reset_tail_pointer(ch->xid_skb); | ||
2312 | ch->xid_skb->len = 0; | ||
2313 | |||
2314 | switch (fsm_getstate(grp->fsm)) { | ||
2315 | case MPCG_STATE_XID7INITI: | ||
2316 | fsm_newstate(grp->fsm, MPCG_STATE_XID7INITZ); | ||
2317 | mpc_validate_xid(mpcginfo); | ||
2318 | break; | ||
2319 | case MPCG_STATE_XID7INITW: | ||
2320 | fsm_newstate(grp->fsm, MPCG_STATE_XID7INITX); | ||
2321 | mpc_validate_xid(mpcginfo); | ||
2322 | break; | ||
2323 | case MPCG_STATE_XID7INITZ: | ||
2324 | case MPCG_STATE_XID7INITX: | ||
2325 | if (grp->outstanding_xid7 == 0) { | ||
2326 | if (grp->outstanding_xid7_p2 > 0) { | ||
2327 | grp->outstanding_xid7 = | ||
2328 | grp->outstanding_xid7_p2; | ||
2329 | grp->outstanding_xid7_p2 = 0; | ||
2330 | } else | ||
2331 | fsm_newstate(grp->fsm, MPCG_STATE_XID7INITF); | ||
2332 | |||
2333 | mpc_validate_xid(mpcginfo); | ||
2334 | fsm_event(grp->fsm, MPCG_EVENT_XID7DONE, dev); | ||
2335 | break; | ||
2336 | } | ||
2337 | mpc_validate_xid(mpcginfo); | ||
2338 | break; | ||
2339 | } | ||
2340 | |||
2341 | kfree(mpcginfo); | ||
2342 | |||
2343 | if (do_debug) | ||
2344 | ctcm_pr_debug("ctcmpc exit: %s(): cp=%i ch=0x%p id=%s\n", | ||
2345 | __FUNCTION__, smp_processor_id(), ch, ch->id); | ||
2346 | return; | ||
2347 | |||
2348 | } | ||
2349 | |||
2350 | /* | ||
2351 | * mpc_action helper of an MPC Group Station FSM action | ||
2352 | * CTCM_PROTO_MPC only | ||
2353 | */ | ||
2354 | static int mpc_send_qllc_discontact(struct net_device *dev) | ||
2355 | { | ||
2356 | int rc = 0; | ||
2357 | __u32 new_len = 0; | ||
2358 | struct sk_buff *skb; | ||
2359 | struct qllc *qllcptr; | ||
2360 | struct ctcm_priv *priv; | ||
2361 | struct mpc_group *grp; | ||
2362 | |||
2363 | ctcm_pr_debug("ctcmpc enter: %s()\n", __FUNCTION__); | ||
2364 | |||
2365 | if (dev == NULL) { | ||
2366 | printk(KERN_INFO "%s() dev=NULL\n", __FUNCTION__); | ||
2367 | rc = 1; | ||
2368 | goto done; | ||
2369 | } | ||
2370 | |||
2371 | priv = dev->priv; | ||
2372 | if (priv == NULL) { | ||
2373 | printk(KERN_INFO "%s() priv=NULL\n", __FUNCTION__); | ||
2374 | rc = 1; | ||
2375 | goto done; | ||
2376 | } | ||
2377 | |||
2378 | grp = priv->mpcg; | ||
2379 | if (grp == NULL) { | ||
2380 | printk(KERN_INFO "%s() grp=NULL\n", __FUNCTION__); | ||
2381 | rc = 1; | ||
2382 | goto done; | ||
2383 | } | ||
2384 | ctcm_pr_info("ctcmpc: %s() GROUP STATE: %s\n", __FUNCTION__, | ||
2385 | mpcg_state_names[grp->saved_state]); | ||
2386 | |||
2387 | switch (grp->saved_state) { | ||
2388 | /* | ||
2389 | * establish conn callback function is | ||
2390 | * preferred method to report failure | ||
2391 | */ | ||
2392 | case MPCG_STATE_XID0IOWAIT: | ||
2393 | case MPCG_STATE_XID0IOWAIX: | ||
2394 | case MPCG_STATE_XID7INITI: | ||
2395 | case MPCG_STATE_XID7INITZ: | ||
2396 | case MPCG_STATE_XID2INITW: | ||
2397 | case MPCG_STATE_XID2INITX: | ||
2398 | case MPCG_STATE_XID7INITW: | ||
2399 | case MPCG_STATE_XID7INITX: | ||
2400 | if (grp->estconnfunc) { | ||
2401 | grp->estconnfunc(grp->port_num, -1, 0); | ||
2402 | grp->estconnfunc = NULL; | ||
2403 | break; | ||
2404 | } | ||
2405 | case MPCG_STATE_FLOWC: | ||
2406 | case MPCG_STATE_READY: | ||
2407 | grp->send_qllc_disc = 2; | ||
2408 | new_len = sizeof(struct qllc); | ||
2409 | qllcptr = kzalloc(new_len, gfp_type() | GFP_DMA); | ||
2410 | if (qllcptr == NULL) { | ||
2411 | printk(KERN_INFO | ||
2412 | "ctcmpc: Out of memory in %s()\n", | ||
2413 | dev->name); | ||
2414 | rc = 1; | ||
2415 | goto done; | ||
2416 | } | ||
2417 | |||
2418 | qllcptr->qllc_address = 0xcc; | ||
2419 | qllcptr->qllc_commands = 0x03; | ||
2420 | |||
2421 | skb = __dev_alloc_skb(new_len, GFP_ATOMIC); | ||
2422 | |||
2423 | if (skb == NULL) { | ||
2424 | printk(KERN_INFO "%s Out of memory in mpc_send_qllc\n", | ||
2425 | dev->name); | ||
2426 | priv->stats.rx_dropped++; | ||
2427 | rc = 1; | ||
2428 | kfree(qllcptr); | ||
2429 | goto done; | ||
2430 | } | ||
2431 | |||
2432 | memcpy(skb_put(skb, new_len), qllcptr, new_len); | ||
2433 | kfree(qllcptr); | ||
2434 | |||
2435 | if (skb_headroom(skb) < 4) { | ||
2436 | printk(KERN_INFO "ctcmpc: %s() Unable to" | ||
2437 | " build discontact for %s\n", | ||
2438 | __FUNCTION__, dev->name); | ||
2439 | rc = 1; | ||
2440 | dev_kfree_skb_any(skb); | ||
2441 | goto done; | ||
2442 | } | ||
2443 | |||
2444 | *((__u32 *)skb_push(skb, 4)) = priv->channel[READ]->pdu_seq; | ||
2445 | priv->channel[READ]->pdu_seq++; | ||
2446 | if (do_debug_data) | ||
2447 | ctcm_pr_debug("ctcmpc: %s ToDCM_pdu_seq= %08x\n", | ||
2448 | __FUNCTION__, priv->channel[READ]->pdu_seq); | ||
2449 | |||
2450 | /* receipt of CC03 resets anticipated sequence number on | ||
2451 | receiving side */ | ||
2452 | priv->channel[READ]->pdu_seq = 0x00; | ||
2453 | skb_reset_mac_header(skb); | ||
2454 | skb->dev = dev; | ||
2455 | skb->protocol = htons(ETH_P_SNAP); | ||
2456 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
2457 | |||
2458 | ctcmpc_dumpit((char *)skb->data, (sizeof(struct qllc) + 4)); | ||
2459 | |||
2460 | netif_rx(skb); | ||
2461 | break; | ||
2462 | default: | ||
2463 | break; | ||
2464 | |||
2465 | } | ||
2466 | |||
2467 | done: | ||
2468 | ctcm_pr_debug("ctcmpc exit: %s()\n", __FUNCTION__); | ||
2469 | return rc; | ||
2470 | } | ||
2471 | /* --- This is the END my friend --- */ | ||
2472 | |||