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