xref: /OK3568_Linux_fs/kernel/drivers/s390/net/ctcm_mpc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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