xref: /OK3568_Linux_fs/kernel/drivers/s390/net/ctcm_fsms.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright IBM Corp. 2001, 2007
4*4882a593Smuzhiyun  * Authors:	Fritz Elfert (felfert@millenux.com)
5*4882a593Smuzhiyun  * 		Peter Tiedemann (ptiedem@de.ibm.com)
6*4882a593Smuzhiyun  *	MPC additions :
7*4882a593Smuzhiyun  *		Belinda Thompson (belindat@us.ibm.com)
8*4882a593Smuzhiyun  *		Andy Richter (richtera@us.ibm.com)
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #undef DEBUG
12*4882a593Smuzhiyun #undef DEBUGDATA
13*4882a593Smuzhiyun #undef DEBUGCCW
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #define KMSG_COMPONENT "ctcm"
16*4882a593Smuzhiyun #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/init.h>
20*4882a593Smuzhiyun #include <linux/kernel.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <linux/errno.h>
23*4882a593Smuzhiyun #include <linux/types.h>
24*4882a593Smuzhiyun #include <linux/interrupt.h>
25*4882a593Smuzhiyun #include <linux/timer.h>
26*4882a593Smuzhiyun #include <linux/bitops.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <linux/signal.h>
29*4882a593Smuzhiyun #include <linux/string.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <linux/ip.h>
32*4882a593Smuzhiyun #include <linux/if_arp.h>
33*4882a593Smuzhiyun #include <linux/tcp.h>
34*4882a593Smuzhiyun #include <linux/skbuff.h>
35*4882a593Smuzhiyun #include <linux/ctype.h>
36*4882a593Smuzhiyun #include <net/dst.h>
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include <linux/io.h>
39*4882a593Smuzhiyun #include <asm/ccwdev.h>
40*4882a593Smuzhiyun #include <asm/ccwgroup.h>
41*4882a593Smuzhiyun #include <linux/uaccess.h>
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #include <asm/idals.h>
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #include "fsm.h"
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #include "ctcm_dbug.h"
48*4882a593Smuzhiyun #include "ctcm_main.h"
49*4882a593Smuzhiyun #include "ctcm_fsms.h"
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun const char *dev_state_names[] = {
52*4882a593Smuzhiyun 	[DEV_STATE_STOPPED]		= "Stopped",
53*4882a593Smuzhiyun 	[DEV_STATE_STARTWAIT_RXTX]	= "StartWait RXTX",
54*4882a593Smuzhiyun 	[DEV_STATE_STARTWAIT_RX]	= "StartWait RX",
55*4882a593Smuzhiyun 	[DEV_STATE_STARTWAIT_TX]	= "StartWait TX",
56*4882a593Smuzhiyun 	[DEV_STATE_STOPWAIT_RXTX]	= "StopWait RXTX",
57*4882a593Smuzhiyun 	[DEV_STATE_STOPWAIT_RX]		= "StopWait RX",
58*4882a593Smuzhiyun 	[DEV_STATE_STOPWAIT_TX]		= "StopWait TX",
59*4882a593Smuzhiyun 	[DEV_STATE_RUNNING]		= "Running",
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun const char *dev_event_names[] = {
63*4882a593Smuzhiyun 	[DEV_EVENT_START]	= "Start",
64*4882a593Smuzhiyun 	[DEV_EVENT_STOP]	= "Stop",
65*4882a593Smuzhiyun 	[DEV_EVENT_RXUP]	= "RX up",
66*4882a593Smuzhiyun 	[DEV_EVENT_TXUP]	= "TX up",
67*4882a593Smuzhiyun 	[DEV_EVENT_RXDOWN]	= "RX down",
68*4882a593Smuzhiyun 	[DEV_EVENT_TXDOWN]	= "TX down",
69*4882a593Smuzhiyun 	[DEV_EVENT_RESTART]	= "Restart",
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun const char *ctc_ch_event_names[] = {
73*4882a593Smuzhiyun 	[CTC_EVENT_IO_SUCCESS]	= "ccw_device success",
74*4882a593Smuzhiyun 	[CTC_EVENT_IO_EBUSY]	= "ccw_device busy",
75*4882a593Smuzhiyun 	[CTC_EVENT_IO_ENODEV]	= "ccw_device enodev",
76*4882a593Smuzhiyun 	[CTC_EVENT_IO_UNKNOWN]	= "ccw_device unknown",
77*4882a593Smuzhiyun 	[CTC_EVENT_ATTNBUSY]	= "Status ATTN & BUSY",
78*4882a593Smuzhiyun 	[CTC_EVENT_ATTN]	= "Status ATTN",
79*4882a593Smuzhiyun 	[CTC_EVENT_BUSY]	= "Status BUSY",
80*4882a593Smuzhiyun 	[CTC_EVENT_UC_RCRESET]	= "Unit check remote reset",
81*4882a593Smuzhiyun 	[CTC_EVENT_UC_RSRESET]	= "Unit check remote system reset",
82*4882a593Smuzhiyun 	[CTC_EVENT_UC_TXTIMEOUT] = "Unit check TX timeout",
83*4882a593Smuzhiyun 	[CTC_EVENT_UC_TXPARITY]	= "Unit check TX parity",
84*4882a593Smuzhiyun 	[CTC_EVENT_UC_HWFAIL]	= "Unit check Hardware failure",
85*4882a593Smuzhiyun 	[CTC_EVENT_UC_RXPARITY]	= "Unit check RX parity",
86*4882a593Smuzhiyun 	[CTC_EVENT_UC_ZERO]	= "Unit check ZERO",
87*4882a593Smuzhiyun 	[CTC_EVENT_UC_UNKNOWN]	= "Unit check Unknown",
88*4882a593Smuzhiyun 	[CTC_EVENT_SC_UNKNOWN]	= "SubChannel check Unknown",
89*4882a593Smuzhiyun 	[CTC_EVENT_MC_FAIL]	= "Machine check failure",
90*4882a593Smuzhiyun 	[CTC_EVENT_MC_GOOD]	= "Machine check operational",
91*4882a593Smuzhiyun 	[CTC_EVENT_IRQ]		= "IRQ normal",
92*4882a593Smuzhiyun 	[CTC_EVENT_FINSTAT]	= "IRQ final",
93*4882a593Smuzhiyun 	[CTC_EVENT_TIMER]	= "Timer",
94*4882a593Smuzhiyun 	[CTC_EVENT_START]	= "Start",
95*4882a593Smuzhiyun 	[CTC_EVENT_STOP]	= "Stop",
96*4882a593Smuzhiyun 	/*
97*4882a593Smuzhiyun 	* additional MPC events
98*4882a593Smuzhiyun 	*/
99*4882a593Smuzhiyun 	[CTC_EVENT_SEND_XID]	= "XID Exchange",
100*4882a593Smuzhiyun 	[CTC_EVENT_RSWEEP_TIMER] = "MPC Group Sweep Timer",
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun const char *ctc_ch_state_names[] = {
104*4882a593Smuzhiyun 	[CTC_STATE_IDLE]	= "Idle",
105*4882a593Smuzhiyun 	[CTC_STATE_STOPPED]	= "Stopped",
106*4882a593Smuzhiyun 	[CTC_STATE_STARTWAIT]	= "StartWait",
107*4882a593Smuzhiyun 	[CTC_STATE_STARTRETRY]	= "StartRetry",
108*4882a593Smuzhiyun 	[CTC_STATE_SETUPWAIT]	= "SetupWait",
109*4882a593Smuzhiyun 	[CTC_STATE_RXINIT]	= "RX init",
110*4882a593Smuzhiyun 	[CTC_STATE_TXINIT]	= "TX init",
111*4882a593Smuzhiyun 	[CTC_STATE_RX]		= "RX",
112*4882a593Smuzhiyun 	[CTC_STATE_TX]		= "TX",
113*4882a593Smuzhiyun 	[CTC_STATE_RXIDLE]	= "RX idle",
114*4882a593Smuzhiyun 	[CTC_STATE_TXIDLE]	= "TX idle",
115*4882a593Smuzhiyun 	[CTC_STATE_RXERR]	= "RX error",
116*4882a593Smuzhiyun 	[CTC_STATE_TXERR]	= "TX error",
117*4882a593Smuzhiyun 	[CTC_STATE_TERM]	= "Terminating",
118*4882a593Smuzhiyun 	[CTC_STATE_DTERM]	= "Restarting",
119*4882a593Smuzhiyun 	[CTC_STATE_NOTOP]	= "Not operational",
120*4882a593Smuzhiyun 	/*
121*4882a593Smuzhiyun 	* additional MPC states
122*4882a593Smuzhiyun 	*/
123*4882a593Smuzhiyun 	[CH_XID0_PENDING]	= "Pending XID0 Start",
124*4882a593Smuzhiyun 	[CH_XID0_INPROGRESS]	= "In XID0 Negotiations ",
125*4882a593Smuzhiyun 	[CH_XID7_PENDING]	= "Pending XID7 P1 Start",
126*4882a593Smuzhiyun 	[CH_XID7_PENDING1]	= "Active XID7 P1 Exchange ",
127*4882a593Smuzhiyun 	[CH_XID7_PENDING2]	= "Pending XID7 P2 Start ",
128*4882a593Smuzhiyun 	[CH_XID7_PENDING3]	= "Active XID7 P2 Exchange ",
129*4882a593Smuzhiyun 	[CH_XID7_PENDING4]	= "XID7 Complete - Pending READY ",
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun static void ctcm_action_nop(fsm_instance *fi, int event, void *arg);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun /*
135*4882a593Smuzhiyun  * ----- static ctcm actions for channel statemachine -----
136*4882a593Smuzhiyun  *
137*4882a593Smuzhiyun */
138*4882a593Smuzhiyun static void chx_txdone(fsm_instance *fi, int event, void *arg);
139*4882a593Smuzhiyun static void chx_rx(fsm_instance *fi, int event, void *arg);
140*4882a593Smuzhiyun static void chx_rxidle(fsm_instance *fi, int event, void *arg);
141*4882a593Smuzhiyun static void chx_firstio(fsm_instance *fi, int event, void *arg);
142*4882a593Smuzhiyun static void ctcm_chx_setmode(fsm_instance *fi, int event, void *arg);
143*4882a593Smuzhiyun static void ctcm_chx_start(fsm_instance *fi, int event, void *arg);
144*4882a593Smuzhiyun static void ctcm_chx_haltio(fsm_instance *fi, int event, void *arg);
145*4882a593Smuzhiyun static void ctcm_chx_stopped(fsm_instance *fi, int event, void *arg);
146*4882a593Smuzhiyun static void ctcm_chx_stop(fsm_instance *fi, int event, void *arg);
147*4882a593Smuzhiyun static void ctcm_chx_fail(fsm_instance *fi, int event, void *arg);
148*4882a593Smuzhiyun static void ctcm_chx_setuperr(fsm_instance *fi, int event, void *arg);
149*4882a593Smuzhiyun static void ctcm_chx_restart(fsm_instance *fi, int event, void *arg);
150*4882a593Smuzhiyun static void ctcm_chx_rxiniterr(fsm_instance *fi, int event, void *arg);
151*4882a593Smuzhiyun static void ctcm_chx_rxinitfail(fsm_instance *fi, int event, void *arg);
152*4882a593Smuzhiyun static void ctcm_chx_rxdisc(fsm_instance *fi, int event, void *arg);
153*4882a593Smuzhiyun static void ctcm_chx_txiniterr(fsm_instance *fi, int event, void *arg);
154*4882a593Smuzhiyun static void ctcm_chx_txretry(fsm_instance *fi, int event, void *arg);
155*4882a593Smuzhiyun static void ctcm_chx_iofatal(fsm_instance *fi, int event, void *arg);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun /*
158*4882a593Smuzhiyun  * ----- static ctcmpc actions for ctcmpc channel statemachine -----
159*4882a593Smuzhiyun  *
160*4882a593Smuzhiyun */
161*4882a593Smuzhiyun static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg);
162*4882a593Smuzhiyun static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg);
163*4882a593Smuzhiyun static void ctcmpc_chx_firstio(fsm_instance *fi, int event, void *arg);
164*4882a593Smuzhiyun /* shared :
165*4882a593Smuzhiyun static void ctcm_chx_setmode(fsm_instance *fi, int event, void *arg);
166*4882a593Smuzhiyun static void ctcm_chx_start(fsm_instance *fi, int event, void *arg);
167*4882a593Smuzhiyun static void ctcm_chx_haltio(fsm_instance *fi, int event, void *arg);
168*4882a593Smuzhiyun static void ctcm_chx_stopped(fsm_instance *fi, int event, void *arg);
169*4882a593Smuzhiyun static void ctcm_chx_stop(fsm_instance *fi, int event, void *arg);
170*4882a593Smuzhiyun static void ctcm_chx_fail(fsm_instance *fi, int event, void *arg);
171*4882a593Smuzhiyun static void ctcm_chx_setuperr(fsm_instance *fi, int event, void *arg);
172*4882a593Smuzhiyun static void ctcm_chx_restart(fsm_instance *fi, int event, void *arg);
173*4882a593Smuzhiyun static void ctcm_chx_rxiniterr(fsm_instance *fi, int event, void *arg);
174*4882a593Smuzhiyun static void ctcm_chx_rxinitfail(fsm_instance *fi, int event, void *arg);
175*4882a593Smuzhiyun static void ctcm_chx_rxdisc(fsm_instance *fi, int event, void *arg);
176*4882a593Smuzhiyun static void ctcm_chx_txiniterr(fsm_instance *fi, int event, void *arg);
177*4882a593Smuzhiyun static void ctcm_chx_txretry(fsm_instance *fi, int event, void *arg);
178*4882a593Smuzhiyun static void ctcm_chx_iofatal(fsm_instance *fi, int event, void *arg);
179*4882a593Smuzhiyun */
180*4882a593Smuzhiyun static void ctcmpc_chx_attn(fsm_instance *fsm, int event, void *arg);
181*4882a593Smuzhiyun static void ctcmpc_chx_attnbusy(fsm_instance *, int, void *);
182*4882a593Smuzhiyun static void ctcmpc_chx_resend(fsm_instance *, int, void *);
183*4882a593Smuzhiyun static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun /**
186*4882a593Smuzhiyun  * Check return code of a preceding ccw_device call, halt_IO etc...
187*4882a593Smuzhiyun  *
188*4882a593Smuzhiyun  * ch	:	The channel, the error belongs to.
189*4882a593Smuzhiyun  * Returns the error code (!= 0) to inspect.
190*4882a593Smuzhiyun  */
ctcm_ccw_check_rc(struct channel * ch,int rc,char * msg)191*4882a593Smuzhiyun void ctcm_ccw_check_rc(struct channel *ch, int rc, char *msg)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
194*4882a593Smuzhiyun 		"%s(%s): %s: %04x\n",
195*4882a593Smuzhiyun 		CTCM_FUNTAIL, ch->id, msg, rc);
196*4882a593Smuzhiyun 	switch (rc) {
197*4882a593Smuzhiyun 	case -EBUSY:
198*4882a593Smuzhiyun 		pr_info("%s: The communication peer is busy\n",
199*4882a593Smuzhiyun 			ch->id);
200*4882a593Smuzhiyun 		fsm_event(ch->fsm, CTC_EVENT_IO_EBUSY, ch);
201*4882a593Smuzhiyun 		break;
202*4882a593Smuzhiyun 	case -ENODEV:
203*4882a593Smuzhiyun 		pr_err("%s: The specified target device is not valid\n",
204*4882a593Smuzhiyun 		       ch->id);
205*4882a593Smuzhiyun 		fsm_event(ch->fsm, CTC_EVENT_IO_ENODEV, ch);
206*4882a593Smuzhiyun 		break;
207*4882a593Smuzhiyun 	default:
208*4882a593Smuzhiyun 		pr_err("An I/O operation resulted in error %04x\n",
209*4882a593Smuzhiyun 		       rc);
210*4882a593Smuzhiyun 		fsm_event(ch->fsm, CTC_EVENT_IO_UNKNOWN, ch);
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
ctcm_purge_skb_queue(struct sk_buff_head * q)214*4882a593Smuzhiyun void ctcm_purge_skb_queue(struct sk_buff_head *q)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	struct sk_buff *skb;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	CTCM_DBF_TEXT(TRACE, CTC_DBF_DEBUG, __func__);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	while ((skb = skb_dequeue(q))) {
221*4882a593Smuzhiyun 		refcount_dec(&skb->users);
222*4882a593Smuzhiyun 		dev_kfree_skb_any(skb);
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun /**
227*4882a593Smuzhiyun  * NOP action for statemachines
228*4882a593Smuzhiyun  */
ctcm_action_nop(fsm_instance * fi,int event,void * arg)229*4882a593Smuzhiyun static void ctcm_action_nop(fsm_instance *fi, int event, void *arg)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun /*
234*4882a593Smuzhiyun  * Actions for channel - statemachines.
235*4882a593Smuzhiyun  */
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun /**
238*4882a593Smuzhiyun  * Normal data has been send. Free the corresponding
239*4882a593Smuzhiyun  * skb (it's in io_queue), reset dev->tbusy and
240*4882a593Smuzhiyun  * revert to idle state.
241*4882a593Smuzhiyun  *
242*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
243*4882a593Smuzhiyun  * event	The event, just happened.
244*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
245*4882a593Smuzhiyun  */
chx_txdone(fsm_instance * fi,int event,void * arg)246*4882a593Smuzhiyun static void chx_txdone(fsm_instance *fi, int event, void *arg)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	struct channel *ch = arg;
249*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
250*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
251*4882a593Smuzhiyun 	struct sk_buff *skb;
252*4882a593Smuzhiyun 	int first = 1;
253*4882a593Smuzhiyun 	int i;
254*4882a593Smuzhiyun 	unsigned long duration;
255*4882a593Smuzhiyun 	unsigned long done_stamp = jiffies;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	CTCM_PR_DEBUG("%s(%s): %s\n", __func__, ch->id, dev->name);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	duration = done_stamp - ch->prof.send_stamp;
260*4882a593Smuzhiyun 	if (duration > ch->prof.tx_time)
261*4882a593Smuzhiyun 		ch->prof.tx_time = duration;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (ch->irb->scsw.cmd.count != 0)
264*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
265*4882a593Smuzhiyun 			"%s(%s): TX not complete, remaining %d bytes",
266*4882a593Smuzhiyun 			     CTCM_FUNTAIL, dev->name, ch->irb->scsw.cmd.count);
267*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
268*4882a593Smuzhiyun 	while ((skb = skb_dequeue(&ch->io_queue))) {
269*4882a593Smuzhiyun 		priv->stats.tx_packets++;
270*4882a593Smuzhiyun 		priv->stats.tx_bytes += skb->len - LL_HEADER_LENGTH;
271*4882a593Smuzhiyun 		if (first) {
272*4882a593Smuzhiyun 			priv->stats.tx_bytes += 2;
273*4882a593Smuzhiyun 			first = 0;
274*4882a593Smuzhiyun 		}
275*4882a593Smuzhiyun 		refcount_dec(&skb->users);
276*4882a593Smuzhiyun 		dev_kfree_skb_irq(skb);
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 	spin_lock(&ch->collect_lock);
279*4882a593Smuzhiyun 	clear_normalized_cda(&ch->ccw[4]);
280*4882a593Smuzhiyun 	if (ch->collect_len > 0) {
281*4882a593Smuzhiyun 		int rc;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		if (ctcm_checkalloc_buffer(ch)) {
284*4882a593Smuzhiyun 			spin_unlock(&ch->collect_lock);
285*4882a593Smuzhiyun 			return;
286*4882a593Smuzhiyun 		}
287*4882a593Smuzhiyun 		ch->trans_skb->data = ch->trans_skb_data;
288*4882a593Smuzhiyun 		skb_reset_tail_pointer(ch->trans_skb);
289*4882a593Smuzhiyun 		ch->trans_skb->len = 0;
290*4882a593Smuzhiyun 		if (ch->prof.maxmulti < (ch->collect_len + 2))
291*4882a593Smuzhiyun 			ch->prof.maxmulti = ch->collect_len + 2;
292*4882a593Smuzhiyun 		if (ch->prof.maxcqueue < skb_queue_len(&ch->collect_queue))
293*4882a593Smuzhiyun 			ch->prof.maxcqueue = skb_queue_len(&ch->collect_queue);
294*4882a593Smuzhiyun 		*((__u16 *)skb_put(ch->trans_skb, 2)) = ch->collect_len + 2;
295*4882a593Smuzhiyun 		i = 0;
296*4882a593Smuzhiyun 		while ((skb = skb_dequeue(&ch->collect_queue))) {
297*4882a593Smuzhiyun 			skb_copy_from_linear_data(skb,
298*4882a593Smuzhiyun 				skb_put(ch->trans_skb, skb->len), skb->len);
299*4882a593Smuzhiyun 			priv->stats.tx_packets++;
300*4882a593Smuzhiyun 			priv->stats.tx_bytes += skb->len - LL_HEADER_LENGTH;
301*4882a593Smuzhiyun 			refcount_dec(&skb->users);
302*4882a593Smuzhiyun 			dev_kfree_skb_irq(skb);
303*4882a593Smuzhiyun 			i++;
304*4882a593Smuzhiyun 		}
305*4882a593Smuzhiyun 		ch->collect_len = 0;
306*4882a593Smuzhiyun 		spin_unlock(&ch->collect_lock);
307*4882a593Smuzhiyun 		ch->ccw[1].count = ch->trans_skb->len;
308*4882a593Smuzhiyun 		fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
309*4882a593Smuzhiyun 		ch->prof.send_stamp = jiffies;
310*4882a593Smuzhiyun 		rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
311*4882a593Smuzhiyun 		ch->prof.doios_multi++;
312*4882a593Smuzhiyun 		if (rc != 0) {
313*4882a593Smuzhiyun 			priv->stats.tx_dropped += i;
314*4882a593Smuzhiyun 			priv->stats.tx_errors += i;
315*4882a593Smuzhiyun 			fsm_deltimer(&ch->timer);
316*4882a593Smuzhiyun 			ctcm_ccw_check_rc(ch, rc, "chained TX");
317*4882a593Smuzhiyun 		}
318*4882a593Smuzhiyun 	} else {
319*4882a593Smuzhiyun 		spin_unlock(&ch->collect_lock);
320*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_TXIDLE);
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 	ctcm_clear_busy_do(dev);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun /**
326*4882a593Smuzhiyun  * Initial data is sent.
327*4882a593Smuzhiyun  * Notify device statemachine that we are up and
328*4882a593Smuzhiyun  * running.
329*4882a593Smuzhiyun  *
330*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
331*4882a593Smuzhiyun  * event	The event, just happened.
332*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
333*4882a593Smuzhiyun  */
ctcm_chx_txidle(fsm_instance * fi,int event,void * arg)334*4882a593Smuzhiyun void ctcm_chx_txidle(fsm_instance *fi, int event, void *arg)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	struct channel *ch = arg;
337*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
338*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	CTCM_PR_DEBUG("%s(%s): %s\n", __func__, ch->id, dev->name);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
343*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_TXIDLE);
344*4882a593Smuzhiyun 	fsm_event(priv->fsm, DEV_EVENT_TXUP, ch->netdev);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun /**
348*4882a593Smuzhiyun  * Got normal data, check for sanity, queue it up, allocate new buffer
349*4882a593Smuzhiyun  * trigger bottom half, and initiate next read.
350*4882a593Smuzhiyun  *
351*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
352*4882a593Smuzhiyun  * event	The event, just happened.
353*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
354*4882a593Smuzhiyun  */
chx_rx(fsm_instance * fi,int event,void * arg)355*4882a593Smuzhiyun static void chx_rx(fsm_instance *fi, int event, void *arg)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	struct channel *ch = arg;
358*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
359*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
360*4882a593Smuzhiyun 	int len = ch->max_bufsize - ch->irb->scsw.cmd.count;
361*4882a593Smuzhiyun 	struct sk_buff *skb = ch->trans_skb;
362*4882a593Smuzhiyun 	__u16 block_len = *((__u16 *)skb->data);
363*4882a593Smuzhiyun 	int check_len;
364*4882a593Smuzhiyun 	int rc;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
367*4882a593Smuzhiyun 	if (len < 8) {
368*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
369*4882a593Smuzhiyun 			"%s(%s): got packet with length %d < 8\n",
370*4882a593Smuzhiyun 					CTCM_FUNTAIL, dev->name, len);
371*4882a593Smuzhiyun 		priv->stats.rx_dropped++;
372*4882a593Smuzhiyun 		priv->stats.rx_length_errors++;
373*4882a593Smuzhiyun 						goto again;
374*4882a593Smuzhiyun 	}
375*4882a593Smuzhiyun 	if (len > ch->max_bufsize) {
376*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
377*4882a593Smuzhiyun 			"%s(%s): got packet with length %d > %d\n",
378*4882a593Smuzhiyun 				CTCM_FUNTAIL, dev->name, len, ch->max_bufsize);
379*4882a593Smuzhiyun 		priv->stats.rx_dropped++;
380*4882a593Smuzhiyun 		priv->stats.rx_length_errors++;
381*4882a593Smuzhiyun 						goto again;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	/*
385*4882a593Smuzhiyun 	 * VM TCP seems to have a bug sending 2 trailing bytes of garbage.
386*4882a593Smuzhiyun 	 */
387*4882a593Smuzhiyun 	switch (ch->protocol) {
388*4882a593Smuzhiyun 	case CTCM_PROTO_S390:
389*4882a593Smuzhiyun 	case CTCM_PROTO_OS390:
390*4882a593Smuzhiyun 		check_len = block_len + 2;
391*4882a593Smuzhiyun 		break;
392*4882a593Smuzhiyun 	default:
393*4882a593Smuzhiyun 		check_len = block_len;
394*4882a593Smuzhiyun 		break;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 	if ((len < block_len) || (len > check_len)) {
397*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
398*4882a593Smuzhiyun 			"%s(%s): got block length %d != rx length %d\n",
399*4882a593Smuzhiyun 				CTCM_FUNTAIL, dev->name, block_len, len);
400*4882a593Smuzhiyun 		if (do_debug)
401*4882a593Smuzhiyun 			ctcmpc_dump_skb(skb, 0);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 		*((__u16 *)skb->data) = len;
404*4882a593Smuzhiyun 		priv->stats.rx_dropped++;
405*4882a593Smuzhiyun 		priv->stats.rx_length_errors++;
406*4882a593Smuzhiyun 						goto again;
407*4882a593Smuzhiyun 	}
408*4882a593Smuzhiyun 	if (block_len > 2) {
409*4882a593Smuzhiyun 		*((__u16 *)skb->data) = block_len - 2;
410*4882a593Smuzhiyun 		ctcm_unpack_skb(ch, skb);
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun  again:
413*4882a593Smuzhiyun 	skb->data = ch->trans_skb_data;
414*4882a593Smuzhiyun 	skb_reset_tail_pointer(skb);
415*4882a593Smuzhiyun 	skb->len = 0;
416*4882a593Smuzhiyun 	if (ctcm_checkalloc_buffer(ch))
417*4882a593Smuzhiyun 		return;
418*4882a593Smuzhiyun 	ch->ccw[1].count = ch->max_bufsize;
419*4882a593Smuzhiyun 	rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
420*4882a593Smuzhiyun 	if (rc != 0)
421*4882a593Smuzhiyun 		ctcm_ccw_check_rc(ch, rc, "normal RX");
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun /**
425*4882a593Smuzhiyun  * Initialize connection by sending a __u16 of value 0.
426*4882a593Smuzhiyun  *
427*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
428*4882a593Smuzhiyun  * event	The event, just happened.
429*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
430*4882a593Smuzhiyun  */
chx_firstio(fsm_instance * fi,int event,void * arg)431*4882a593Smuzhiyun static void chx_firstio(fsm_instance *fi, int event, void *arg)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun 	int rc;
434*4882a593Smuzhiyun 	struct channel *ch = arg;
435*4882a593Smuzhiyun 	int fsmstate = fsm_getstate(fi);
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
438*4882a593Smuzhiyun 		"%s(%s) : %02x",
439*4882a593Smuzhiyun 		CTCM_FUNTAIL, ch->id, fsmstate);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	ch->sense_rc = 0;	/* reset unit check report control */
442*4882a593Smuzhiyun 	if (fsmstate == CTC_STATE_TXIDLE)
443*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
444*4882a593Smuzhiyun 			"%s(%s): remote side issued READ?, init.\n",
445*4882a593Smuzhiyun 				CTCM_FUNTAIL, ch->id);
446*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
447*4882a593Smuzhiyun 	if (ctcm_checkalloc_buffer(ch))
448*4882a593Smuzhiyun 		return;
449*4882a593Smuzhiyun 	if ((fsmstate == CTC_STATE_SETUPWAIT) &&
450*4882a593Smuzhiyun 	    (ch->protocol == CTCM_PROTO_OS390)) {
451*4882a593Smuzhiyun 		/* OS/390 resp. z/OS */
452*4882a593Smuzhiyun 		if (CHANNEL_DIRECTION(ch->flags) == CTCM_READ) {
453*4882a593Smuzhiyun 			*((__u16 *)ch->trans_skb->data) = CTCM_INITIAL_BLOCKLEN;
454*4882a593Smuzhiyun 			fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC,
455*4882a593Smuzhiyun 				     CTC_EVENT_TIMER, ch);
456*4882a593Smuzhiyun 			chx_rxidle(fi, event, arg);
457*4882a593Smuzhiyun 		} else {
458*4882a593Smuzhiyun 			struct net_device *dev = ch->netdev;
459*4882a593Smuzhiyun 			struct ctcm_priv *priv = dev->ml_priv;
460*4882a593Smuzhiyun 			fsm_newstate(fi, CTC_STATE_TXIDLE);
461*4882a593Smuzhiyun 			fsm_event(priv->fsm, DEV_EVENT_TXUP, dev);
462*4882a593Smuzhiyun 		}
463*4882a593Smuzhiyun 		return;
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 	/*
466*4882a593Smuzhiyun 	 * Don't setup a timer for receiving the initial RX frame
467*4882a593Smuzhiyun 	 * if in compatibility mode, since VM TCP delays the initial
468*4882a593Smuzhiyun 	 * frame until it has some data to send.
469*4882a593Smuzhiyun 	 */
470*4882a593Smuzhiyun 	if ((CHANNEL_DIRECTION(ch->flags) == CTCM_WRITE) ||
471*4882a593Smuzhiyun 	    (ch->protocol != CTCM_PROTO_S390))
472*4882a593Smuzhiyun 		fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	*((__u16 *)ch->trans_skb->data) = CTCM_INITIAL_BLOCKLEN;
475*4882a593Smuzhiyun 	ch->ccw[1].count = 2;	/* Transfer only length */
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	fsm_newstate(fi, (CHANNEL_DIRECTION(ch->flags) == CTCM_READ)
478*4882a593Smuzhiyun 		     ? CTC_STATE_RXINIT : CTC_STATE_TXINIT);
479*4882a593Smuzhiyun 	rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
480*4882a593Smuzhiyun 	if (rc != 0) {
481*4882a593Smuzhiyun 		fsm_deltimer(&ch->timer);
482*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_SETUPWAIT);
483*4882a593Smuzhiyun 		ctcm_ccw_check_rc(ch, rc, "init IO");
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun 	/*
486*4882a593Smuzhiyun 	 * If in compatibility mode since we don't setup a timer, we
487*4882a593Smuzhiyun 	 * also signal RX channel up immediately. This enables us
488*4882a593Smuzhiyun 	 * to send packets early which in turn usually triggers some
489*4882a593Smuzhiyun 	 * reply from VM TCP which brings up the RX channel to it's
490*4882a593Smuzhiyun 	 * final state.
491*4882a593Smuzhiyun 	 */
492*4882a593Smuzhiyun 	if ((CHANNEL_DIRECTION(ch->flags) == CTCM_READ) &&
493*4882a593Smuzhiyun 	    (ch->protocol == CTCM_PROTO_S390)) {
494*4882a593Smuzhiyun 		struct net_device *dev = ch->netdev;
495*4882a593Smuzhiyun 		struct ctcm_priv *priv = dev->ml_priv;
496*4882a593Smuzhiyun 		fsm_event(priv->fsm, DEV_EVENT_RXUP, dev);
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun /**
501*4882a593Smuzhiyun  * Got initial data, check it. If OK,
502*4882a593Smuzhiyun  * notify device statemachine that we are up and
503*4882a593Smuzhiyun  * running.
504*4882a593Smuzhiyun  *
505*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
506*4882a593Smuzhiyun  * event	The event, just happened.
507*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
508*4882a593Smuzhiyun  */
chx_rxidle(fsm_instance * fi,int event,void * arg)509*4882a593Smuzhiyun static void chx_rxidle(fsm_instance *fi, int event, void *arg)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	struct channel *ch = arg;
512*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
513*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
514*4882a593Smuzhiyun 	__u16 buflen;
515*4882a593Smuzhiyun 	int rc;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
518*4882a593Smuzhiyun 	buflen = *((__u16 *)ch->trans_skb->data);
519*4882a593Smuzhiyun 	CTCM_PR_DEBUG("%s: %s: Initial RX count = %d\n",
520*4882a593Smuzhiyun 			__func__, dev->name, buflen);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	if (buflen >= CTCM_INITIAL_BLOCKLEN) {
523*4882a593Smuzhiyun 		if (ctcm_checkalloc_buffer(ch))
524*4882a593Smuzhiyun 			return;
525*4882a593Smuzhiyun 		ch->ccw[1].count = ch->max_bufsize;
526*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_RXIDLE);
527*4882a593Smuzhiyun 		rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
528*4882a593Smuzhiyun 		if (rc != 0) {
529*4882a593Smuzhiyun 			fsm_newstate(fi, CTC_STATE_RXINIT);
530*4882a593Smuzhiyun 			ctcm_ccw_check_rc(ch, rc, "initial RX");
531*4882a593Smuzhiyun 		} else
532*4882a593Smuzhiyun 			fsm_event(priv->fsm, DEV_EVENT_RXUP, dev);
533*4882a593Smuzhiyun 	} else {
534*4882a593Smuzhiyun 		CTCM_PR_DEBUG("%s: %s: Initial RX count %d not %d\n",
535*4882a593Smuzhiyun 				__func__, dev->name,
536*4882a593Smuzhiyun 					buflen, CTCM_INITIAL_BLOCKLEN);
537*4882a593Smuzhiyun 		chx_firstio(fi, event, arg);
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun /**
542*4882a593Smuzhiyun  * Set channel into extended mode.
543*4882a593Smuzhiyun  *
544*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
545*4882a593Smuzhiyun  * event	The event, just happened.
546*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
547*4882a593Smuzhiyun  */
ctcm_chx_setmode(fsm_instance * fi,int event,void * arg)548*4882a593Smuzhiyun static void ctcm_chx_setmode(fsm_instance *fi, int event, void *arg)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun 	struct channel *ch = arg;
551*4882a593Smuzhiyun 	int rc;
552*4882a593Smuzhiyun 	unsigned long saveflags = 0;
553*4882a593Smuzhiyun 	int timeout = CTCM_TIME_5_SEC;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
556*4882a593Smuzhiyun 	if (IS_MPC(ch)) {
557*4882a593Smuzhiyun 		timeout = 1500;
558*4882a593Smuzhiyun 		CTCM_PR_DEBUG("enter %s: cp=%i ch=0x%p id=%s\n",
559*4882a593Smuzhiyun 				__func__, smp_processor_id(), ch, ch->id);
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 	fsm_addtimer(&ch->timer, timeout, CTC_EVENT_TIMER, ch);
562*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_SETUPWAIT);
563*4882a593Smuzhiyun 	CTCM_CCW_DUMP((char *)&ch->ccw[6], sizeof(struct ccw1) * 2);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	if (event == CTC_EVENT_TIMER)	/* only for timer not yet locked */
566*4882a593Smuzhiyun 		spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
567*4882a593Smuzhiyun 			/* Such conditional locking is undeterministic in
568*4882a593Smuzhiyun 			 * static view. => ignore sparse warnings here. */
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	rc = ccw_device_start(ch->cdev, &ch->ccw[6], 0, 0xff, 0);
571*4882a593Smuzhiyun 	if (event == CTC_EVENT_TIMER)	/* see above comments */
572*4882a593Smuzhiyun 		spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
573*4882a593Smuzhiyun 	if (rc != 0) {
574*4882a593Smuzhiyun 		fsm_deltimer(&ch->timer);
575*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_STARTWAIT);
576*4882a593Smuzhiyun 		ctcm_ccw_check_rc(ch, rc, "set Mode");
577*4882a593Smuzhiyun 	} else
578*4882a593Smuzhiyun 		ch->retry = 0;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun /**
582*4882a593Smuzhiyun  * Setup channel.
583*4882a593Smuzhiyun  *
584*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
585*4882a593Smuzhiyun  * event	The event, just happened.
586*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
587*4882a593Smuzhiyun  */
ctcm_chx_start(fsm_instance * fi,int event,void * arg)588*4882a593Smuzhiyun static void ctcm_chx_start(fsm_instance *fi, int event, void *arg)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun 	struct channel *ch	= arg;
591*4882a593Smuzhiyun 	unsigned long saveflags;
592*4882a593Smuzhiyun 	int rc;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, "%s(%s): %s",
595*4882a593Smuzhiyun 		CTCM_FUNTAIL, ch->id,
596*4882a593Smuzhiyun 		(CHANNEL_DIRECTION(ch->flags) == CTCM_READ) ? "RX" : "TX");
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (ch->trans_skb != NULL) {
599*4882a593Smuzhiyun 		clear_normalized_cda(&ch->ccw[1]);
600*4882a593Smuzhiyun 		dev_kfree_skb(ch->trans_skb);
601*4882a593Smuzhiyun 		ch->trans_skb = NULL;
602*4882a593Smuzhiyun 	}
603*4882a593Smuzhiyun 	if (CHANNEL_DIRECTION(ch->flags) == CTCM_READ) {
604*4882a593Smuzhiyun 		ch->ccw[1].cmd_code = CCW_CMD_READ;
605*4882a593Smuzhiyun 		ch->ccw[1].flags = CCW_FLAG_SLI;
606*4882a593Smuzhiyun 		ch->ccw[1].count = 0;
607*4882a593Smuzhiyun 	} else {
608*4882a593Smuzhiyun 		ch->ccw[1].cmd_code = CCW_CMD_WRITE;
609*4882a593Smuzhiyun 		ch->ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
610*4882a593Smuzhiyun 		ch->ccw[1].count = 0;
611*4882a593Smuzhiyun 	}
612*4882a593Smuzhiyun 	if (ctcm_checkalloc_buffer(ch)) {
613*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
614*4882a593Smuzhiyun 			"%s(%s): %s trans_skb alloc delayed "
615*4882a593Smuzhiyun 			"until first transfer",
616*4882a593Smuzhiyun 			CTCM_FUNTAIL, ch->id,
617*4882a593Smuzhiyun 			(CHANNEL_DIRECTION(ch->flags) == CTCM_READ) ?
618*4882a593Smuzhiyun 				"RX" : "TX");
619*4882a593Smuzhiyun 	}
620*4882a593Smuzhiyun 	ch->ccw[0].cmd_code = CCW_CMD_PREPARE;
621*4882a593Smuzhiyun 	ch->ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
622*4882a593Smuzhiyun 	ch->ccw[0].count = 0;
623*4882a593Smuzhiyun 	ch->ccw[0].cda = 0;
624*4882a593Smuzhiyun 	ch->ccw[2].cmd_code = CCW_CMD_NOOP;	/* jointed CE + DE */
625*4882a593Smuzhiyun 	ch->ccw[2].flags = CCW_FLAG_SLI;
626*4882a593Smuzhiyun 	ch->ccw[2].count = 0;
627*4882a593Smuzhiyun 	ch->ccw[2].cda = 0;
628*4882a593Smuzhiyun 	memcpy(&ch->ccw[3], &ch->ccw[0], sizeof(struct ccw1) * 3);
629*4882a593Smuzhiyun 	ch->ccw[4].cda = 0;
630*4882a593Smuzhiyun 	ch->ccw[4].flags &= ~CCW_FLAG_IDA;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_STARTWAIT);
633*4882a593Smuzhiyun 	fsm_addtimer(&ch->timer, 1000, CTC_EVENT_TIMER, ch);
634*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
635*4882a593Smuzhiyun 	rc = ccw_device_halt(ch->cdev, 0);
636*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
637*4882a593Smuzhiyun 	if (rc != 0) {
638*4882a593Smuzhiyun 		if (rc != -EBUSY)
639*4882a593Smuzhiyun 			fsm_deltimer(&ch->timer);
640*4882a593Smuzhiyun 		ctcm_ccw_check_rc(ch, rc, "initial HaltIO");
641*4882a593Smuzhiyun 	}
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun /**
645*4882a593Smuzhiyun  * Shutdown a channel.
646*4882a593Smuzhiyun  *
647*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
648*4882a593Smuzhiyun  * event	The event, just happened.
649*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
650*4882a593Smuzhiyun  */
ctcm_chx_haltio(fsm_instance * fi,int event,void * arg)651*4882a593Smuzhiyun static void ctcm_chx_haltio(fsm_instance *fi, int event, void *arg)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun 	struct channel *ch = arg;
654*4882a593Smuzhiyun 	unsigned long saveflags = 0;
655*4882a593Smuzhiyun 	int rc;
656*4882a593Smuzhiyun 	int oldstate;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
659*4882a593Smuzhiyun 	if (IS_MPC(ch))
660*4882a593Smuzhiyun 		fsm_deltimer(&ch->sweep_timer);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	if (event == CTC_EVENT_STOP)	/* only for STOP not yet locked */
665*4882a593Smuzhiyun 		spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
666*4882a593Smuzhiyun 			/* Such conditional locking is undeterministic in
667*4882a593Smuzhiyun 			 * static view. => ignore sparse warnings here. */
668*4882a593Smuzhiyun 	oldstate = fsm_getstate(fi);
669*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_TERM);
670*4882a593Smuzhiyun 	rc = ccw_device_halt(ch->cdev, 0);
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	if (event == CTC_EVENT_STOP)
673*4882a593Smuzhiyun 		spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
674*4882a593Smuzhiyun 			/* see remark above about conditional locking */
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	if (rc != 0 && rc != -EBUSY) {
677*4882a593Smuzhiyun 		fsm_deltimer(&ch->timer);
678*4882a593Smuzhiyun 		if (event != CTC_EVENT_STOP) {
679*4882a593Smuzhiyun 			fsm_newstate(fi, oldstate);
680*4882a593Smuzhiyun 			ctcm_ccw_check_rc(ch, rc, (char *)__func__);
681*4882a593Smuzhiyun 		}
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun /**
686*4882a593Smuzhiyun  * Cleanup helper for chx_fail and chx_stopped
687*4882a593Smuzhiyun  * cleanup channels queue and notify interface statemachine.
688*4882a593Smuzhiyun  *
689*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
690*4882a593Smuzhiyun  * state	The next state (depending on caller).
691*4882a593Smuzhiyun  * ch		The channel to operate on.
692*4882a593Smuzhiyun  */
ctcm_chx_cleanup(fsm_instance * fi,int state,struct channel * ch)693*4882a593Smuzhiyun static void ctcm_chx_cleanup(fsm_instance *fi, int state,
694*4882a593Smuzhiyun 		struct channel *ch)
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
697*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(SETUP, CTC_DBF_NOTICE,
700*4882a593Smuzhiyun 			"%s(%s): %s[%d]\n",
701*4882a593Smuzhiyun 			CTCM_FUNTAIL, dev->name, ch->id, state);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
704*4882a593Smuzhiyun 	if (IS_MPC(ch))
705*4882a593Smuzhiyun 		fsm_deltimer(&ch->sweep_timer);
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	fsm_newstate(fi, state);
708*4882a593Smuzhiyun 	if (state == CTC_STATE_STOPPED && ch->trans_skb != NULL) {
709*4882a593Smuzhiyun 		clear_normalized_cda(&ch->ccw[1]);
710*4882a593Smuzhiyun 		dev_kfree_skb_any(ch->trans_skb);
711*4882a593Smuzhiyun 		ch->trans_skb = NULL;
712*4882a593Smuzhiyun 	}
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	ch->th_seg = 0x00;
715*4882a593Smuzhiyun 	ch->th_seq_num = 0x00;
716*4882a593Smuzhiyun 	if (CHANNEL_DIRECTION(ch->flags) == CTCM_READ) {
717*4882a593Smuzhiyun 		skb_queue_purge(&ch->io_queue);
718*4882a593Smuzhiyun 		fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev);
719*4882a593Smuzhiyun 	} else {
720*4882a593Smuzhiyun 		ctcm_purge_skb_queue(&ch->io_queue);
721*4882a593Smuzhiyun 		if (IS_MPC(ch))
722*4882a593Smuzhiyun 			ctcm_purge_skb_queue(&ch->sweep_queue);
723*4882a593Smuzhiyun 		spin_lock(&ch->collect_lock);
724*4882a593Smuzhiyun 		ctcm_purge_skb_queue(&ch->collect_queue);
725*4882a593Smuzhiyun 		ch->collect_len = 0;
726*4882a593Smuzhiyun 		spin_unlock(&ch->collect_lock);
727*4882a593Smuzhiyun 		fsm_event(priv->fsm, DEV_EVENT_TXDOWN, dev);
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun /**
732*4882a593Smuzhiyun  * A channel has successfully been halted.
733*4882a593Smuzhiyun  * Cleanup it's queue and notify interface statemachine.
734*4882a593Smuzhiyun  *
735*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
736*4882a593Smuzhiyun  * event	The event, just happened.
737*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
738*4882a593Smuzhiyun  */
ctcm_chx_stopped(fsm_instance * fi,int event,void * arg)739*4882a593Smuzhiyun static void ctcm_chx_stopped(fsm_instance *fi, int event, void *arg)
740*4882a593Smuzhiyun {
741*4882a593Smuzhiyun 	ctcm_chx_cleanup(fi, CTC_STATE_STOPPED, arg);
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun /**
745*4882a593Smuzhiyun  * A stop command from device statemachine arrived and we are in
746*4882a593Smuzhiyun  * not operational mode. Set state to stopped.
747*4882a593Smuzhiyun  *
748*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
749*4882a593Smuzhiyun  * event	The event, just happened.
750*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
751*4882a593Smuzhiyun  */
ctcm_chx_stop(fsm_instance * fi,int event,void * arg)752*4882a593Smuzhiyun static void ctcm_chx_stop(fsm_instance *fi, int event, void *arg)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_STOPPED);
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun /**
758*4882a593Smuzhiyun  * A machine check for no path, not operational status or gone device has
759*4882a593Smuzhiyun  * happened.
760*4882a593Smuzhiyun  * Cleanup queue and notify interface statemachine.
761*4882a593Smuzhiyun  *
762*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
763*4882a593Smuzhiyun  * event	The event, just happened.
764*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
765*4882a593Smuzhiyun  */
ctcm_chx_fail(fsm_instance * fi,int event,void * arg)766*4882a593Smuzhiyun static void ctcm_chx_fail(fsm_instance *fi, int event, void *arg)
767*4882a593Smuzhiyun {
768*4882a593Smuzhiyun 	ctcm_chx_cleanup(fi, CTC_STATE_NOTOP, arg);
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun /**
772*4882a593Smuzhiyun  * Handle error during setup of channel.
773*4882a593Smuzhiyun  *
774*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
775*4882a593Smuzhiyun  * event	The event, just happened.
776*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
777*4882a593Smuzhiyun  */
ctcm_chx_setuperr(fsm_instance * fi,int event,void * arg)778*4882a593Smuzhiyun static void ctcm_chx_setuperr(fsm_instance *fi, int event, void *arg)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun 	struct channel *ch = arg;
781*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
782*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	/*
785*4882a593Smuzhiyun 	 * Special case: Got UC_RCRESET on setmode.
786*4882a593Smuzhiyun 	 * This means that remote side isn't setup. In this case
787*4882a593Smuzhiyun 	 * simply retry after some 10 secs...
788*4882a593Smuzhiyun 	 */
789*4882a593Smuzhiyun 	if ((fsm_getstate(fi) == CTC_STATE_SETUPWAIT) &&
790*4882a593Smuzhiyun 	    ((event == CTC_EVENT_UC_RCRESET) ||
791*4882a593Smuzhiyun 	     (event == CTC_EVENT_UC_RSRESET))) {
792*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_STARTRETRY);
793*4882a593Smuzhiyun 		fsm_deltimer(&ch->timer);
794*4882a593Smuzhiyun 		fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
795*4882a593Smuzhiyun 		if (!IS_MPC(ch) &&
796*4882a593Smuzhiyun 		    (CHANNEL_DIRECTION(ch->flags) == CTCM_READ)) {
797*4882a593Smuzhiyun 			int rc = ccw_device_halt(ch->cdev, 0);
798*4882a593Smuzhiyun 			if (rc != 0)
799*4882a593Smuzhiyun 				ctcm_ccw_check_rc(ch, rc,
800*4882a593Smuzhiyun 					"HaltIO in chx_setuperr");
801*4882a593Smuzhiyun 		}
802*4882a593Smuzhiyun 		return;
803*4882a593Smuzhiyun 	}
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(ERROR, CTC_DBF_CRIT,
806*4882a593Smuzhiyun 		"%s(%s) : %s error during %s channel setup state=%s\n",
807*4882a593Smuzhiyun 		CTCM_FUNTAIL, dev->name, ctc_ch_event_names[event],
808*4882a593Smuzhiyun 		(CHANNEL_DIRECTION(ch->flags) == CTCM_READ) ? "RX" : "TX",
809*4882a593Smuzhiyun 		fsm_getstate_str(fi));
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	if (CHANNEL_DIRECTION(ch->flags) == CTCM_READ) {
812*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_RXERR);
813*4882a593Smuzhiyun 		fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev);
814*4882a593Smuzhiyun 	} else {
815*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_TXERR);
816*4882a593Smuzhiyun 		fsm_event(priv->fsm, DEV_EVENT_TXDOWN, dev);
817*4882a593Smuzhiyun 	}
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun /**
821*4882a593Smuzhiyun  * Restart a channel after an error.
822*4882a593Smuzhiyun  *
823*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
824*4882a593Smuzhiyun  * event	The event, just happened.
825*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
826*4882a593Smuzhiyun  */
ctcm_chx_restart(fsm_instance * fi,int event,void * arg)827*4882a593Smuzhiyun static void ctcm_chx_restart(fsm_instance *fi, int event, void *arg)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	struct channel *ch = arg;
830*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
831*4882a593Smuzhiyun 	unsigned long saveflags = 0;
832*4882a593Smuzhiyun 	int oldstate;
833*4882a593Smuzhiyun 	int rc;
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
836*4882a593Smuzhiyun 		"%s: %s[%d] of %s\n",
837*4882a593Smuzhiyun 			CTCM_FUNTAIL, ch->id, event, dev->name);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
842*4882a593Smuzhiyun 	oldstate = fsm_getstate(fi);
843*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_STARTWAIT);
844*4882a593Smuzhiyun 	if (event == CTC_EVENT_TIMER)	/* only for timer not yet locked */
845*4882a593Smuzhiyun 		spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
846*4882a593Smuzhiyun 			/* Such conditional locking is a known problem for
847*4882a593Smuzhiyun 			 * sparse because its undeterministic in static view.
848*4882a593Smuzhiyun 			 * Warnings should be ignored here. */
849*4882a593Smuzhiyun 	rc = ccw_device_halt(ch->cdev, 0);
850*4882a593Smuzhiyun 	if (event == CTC_EVENT_TIMER)
851*4882a593Smuzhiyun 		spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
852*4882a593Smuzhiyun 	if (rc != 0) {
853*4882a593Smuzhiyun 		if (rc != -EBUSY) {
854*4882a593Smuzhiyun 		    fsm_deltimer(&ch->timer);
855*4882a593Smuzhiyun 		    fsm_newstate(fi, oldstate);
856*4882a593Smuzhiyun 		}
857*4882a593Smuzhiyun 		ctcm_ccw_check_rc(ch, rc, "HaltIO in ctcm_chx_restart");
858*4882a593Smuzhiyun 	}
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun /**
862*4882a593Smuzhiyun  * Handle error during RX initial handshake (exchange of
863*4882a593Smuzhiyun  * 0-length block header)
864*4882a593Smuzhiyun  *
865*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
866*4882a593Smuzhiyun  * event	The event, just happened.
867*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
868*4882a593Smuzhiyun  */
ctcm_chx_rxiniterr(fsm_instance * fi,int event,void * arg)869*4882a593Smuzhiyun static void ctcm_chx_rxiniterr(fsm_instance *fi, int event, void *arg)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun 	struct channel *ch = arg;
872*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
873*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	if (event == CTC_EVENT_TIMER) {
876*4882a593Smuzhiyun 		if (!IS_MPCDEV(dev))
877*4882a593Smuzhiyun 			/* TODO : check if MPC deletes timer somewhere */
878*4882a593Smuzhiyun 			fsm_deltimer(&ch->timer);
879*4882a593Smuzhiyun 		if (ch->retry++ < 3)
880*4882a593Smuzhiyun 			ctcm_chx_restart(fi, event, arg);
881*4882a593Smuzhiyun 		else {
882*4882a593Smuzhiyun 			fsm_newstate(fi, CTC_STATE_RXERR);
883*4882a593Smuzhiyun 			fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev);
884*4882a593Smuzhiyun 		}
885*4882a593Smuzhiyun 	} else {
886*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
887*4882a593Smuzhiyun 			"%s(%s): %s in %s", CTCM_FUNTAIL, ch->id,
888*4882a593Smuzhiyun 			ctc_ch_event_names[event], fsm_getstate_str(fi));
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 		dev_warn(&dev->dev,
891*4882a593Smuzhiyun 			"Initialization failed with RX/TX init handshake "
892*4882a593Smuzhiyun 			"error %s\n", ctc_ch_event_names[event]);
893*4882a593Smuzhiyun 	}
894*4882a593Smuzhiyun }
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun /**
897*4882a593Smuzhiyun  * Notify device statemachine if we gave up initialization
898*4882a593Smuzhiyun  * of RX channel.
899*4882a593Smuzhiyun  *
900*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
901*4882a593Smuzhiyun  * event	The event, just happened.
902*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
903*4882a593Smuzhiyun  */
ctcm_chx_rxinitfail(fsm_instance * fi,int event,void * arg)904*4882a593Smuzhiyun static void ctcm_chx_rxinitfail(fsm_instance *fi, int event, void *arg)
905*4882a593Smuzhiyun {
906*4882a593Smuzhiyun 	struct channel *ch = arg;
907*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
908*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
911*4882a593Smuzhiyun 			"%s(%s): RX %s busy, init. fail",
912*4882a593Smuzhiyun 				CTCM_FUNTAIL, dev->name, ch->id);
913*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_RXERR);
914*4882a593Smuzhiyun 	fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev);
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun /**
918*4882a593Smuzhiyun  * Handle RX Unit check remote reset (remote disconnected)
919*4882a593Smuzhiyun  *
920*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
921*4882a593Smuzhiyun  * event	The event, just happened.
922*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
923*4882a593Smuzhiyun  */
ctcm_chx_rxdisc(fsm_instance * fi,int event,void * arg)924*4882a593Smuzhiyun static void ctcm_chx_rxdisc(fsm_instance *fi, int event, void *arg)
925*4882a593Smuzhiyun {
926*4882a593Smuzhiyun 	struct channel *ch = arg;
927*4882a593Smuzhiyun 	struct channel *ch2;
928*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
929*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
932*4882a593Smuzhiyun 			"%s: %s: remote disconnect - re-init ...",
933*4882a593Smuzhiyun 				CTCM_FUNTAIL, dev->name);
934*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
935*4882a593Smuzhiyun 	/*
936*4882a593Smuzhiyun 	 * Notify device statemachine
937*4882a593Smuzhiyun 	 */
938*4882a593Smuzhiyun 	fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev);
939*4882a593Smuzhiyun 	fsm_event(priv->fsm, DEV_EVENT_TXDOWN, dev);
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_DTERM);
942*4882a593Smuzhiyun 	ch2 = priv->channel[CTCM_WRITE];
943*4882a593Smuzhiyun 	fsm_newstate(ch2->fsm, CTC_STATE_DTERM);
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	ccw_device_halt(ch->cdev, 0);
946*4882a593Smuzhiyun 	ccw_device_halt(ch2->cdev, 0);
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun /**
950*4882a593Smuzhiyun  * Handle error during TX channel initialization.
951*4882a593Smuzhiyun  *
952*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
953*4882a593Smuzhiyun  * event	The event, just happened.
954*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
955*4882a593Smuzhiyun  */
ctcm_chx_txiniterr(fsm_instance * fi,int event,void * arg)956*4882a593Smuzhiyun static void ctcm_chx_txiniterr(fsm_instance *fi, int event, void *arg)
957*4882a593Smuzhiyun {
958*4882a593Smuzhiyun 	struct channel *ch = arg;
959*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
960*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 	if (event == CTC_EVENT_TIMER) {
963*4882a593Smuzhiyun 		fsm_deltimer(&ch->timer);
964*4882a593Smuzhiyun 		if (ch->retry++ < 3)
965*4882a593Smuzhiyun 			ctcm_chx_restart(fi, event, arg);
966*4882a593Smuzhiyun 		else {
967*4882a593Smuzhiyun 			fsm_newstate(fi, CTC_STATE_TXERR);
968*4882a593Smuzhiyun 			fsm_event(priv->fsm, DEV_EVENT_TXDOWN, dev);
969*4882a593Smuzhiyun 		}
970*4882a593Smuzhiyun 	} else {
971*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
972*4882a593Smuzhiyun 			"%s(%s): %s in %s", CTCM_FUNTAIL, ch->id,
973*4882a593Smuzhiyun 			ctc_ch_event_names[event], fsm_getstate_str(fi));
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 		dev_warn(&dev->dev,
976*4882a593Smuzhiyun 			"Initialization failed with RX/TX init handshake "
977*4882a593Smuzhiyun 			"error %s\n", ctc_ch_event_names[event]);
978*4882a593Smuzhiyun 	}
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun /**
982*4882a593Smuzhiyun  * Handle TX timeout by retrying operation.
983*4882a593Smuzhiyun  *
984*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
985*4882a593Smuzhiyun  * event	The event, just happened.
986*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
987*4882a593Smuzhiyun  */
ctcm_chx_txretry(fsm_instance * fi,int event,void * arg)988*4882a593Smuzhiyun static void ctcm_chx_txretry(fsm_instance *fi, int event, void *arg)
989*4882a593Smuzhiyun {
990*4882a593Smuzhiyun 	struct channel *ch = arg;
991*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
992*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
993*4882a593Smuzhiyun 	struct sk_buff *skb;
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	CTCM_PR_DEBUG("Enter: %s: cp=%i ch=0x%p id=%s\n",
996*4882a593Smuzhiyun 			__func__, smp_processor_id(), ch, ch->id);
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
999*4882a593Smuzhiyun 	if (ch->retry++ > 3) {
1000*4882a593Smuzhiyun 		struct mpc_group *gptr = priv->mpcg;
1001*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(TRACE, CTC_DBF_INFO,
1002*4882a593Smuzhiyun 				"%s: %s: retries exceeded",
1003*4882a593Smuzhiyun 					CTCM_FUNTAIL, ch->id);
1004*4882a593Smuzhiyun 		fsm_event(priv->fsm, DEV_EVENT_TXDOWN, dev);
1005*4882a593Smuzhiyun 		/* call restart if not MPC or if MPC and mpcg fsm is ready.
1006*4882a593Smuzhiyun 			use gptr as mpc indicator */
1007*4882a593Smuzhiyun 		if (!(gptr && (fsm_getstate(gptr->fsm) != MPCG_STATE_READY)))
1008*4882a593Smuzhiyun 			ctcm_chx_restart(fi, event, arg);
1009*4882a593Smuzhiyun 				goto done;
1010*4882a593Smuzhiyun 	}
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
1013*4882a593Smuzhiyun 			"%s : %s: retry %d",
1014*4882a593Smuzhiyun 				CTCM_FUNTAIL, ch->id, ch->retry);
1015*4882a593Smuzhiyun 	skb = skb_peek(&ch->io_queue);
1016*4882a593Smuzhiyun 	if (skb) {
1017*4882a593Smuzhiyun 		int rc = 0;
1018*4882a593Smuzhiyun 		unsigned long saveflags = 0;
1019*4882a593Smuzhiyun 		clear_normalized_cda(&ch->ccw[4]);
1020*4882a593Smuzhiyun 		ch->ccw[4].count = skb->len;
1021*4882a593Smuzhiyun 		if (set_normalized_cda(&ch->ccw[4], skb->data)) {
1022*4882a593Smuzhiyun 			CTCM_DBF_TEXT_(TRACE, CTC_DBF_INFO,
1023*4882a593Smuzhiyun 				"%s: %s: IDAL alloc failed",
1024*4882a593Smuzhiyun 						CTCM_FUNTAIL, ch->id);
1025*4882a593Smuzhiyun 			fsm_event(priv->fsm, DEV_EVENT_TXDOWN, dev);
1026*4882a593Smuzhiyun 			ctcm_chx_restart(fi, event, arg);
1027*4882a593Smuzhiyun 				goto done;
1028*4882a593Smuzhiyun 		}
1029*4882a593Smuzhiyun 		fsm_addtimer(&ch->timer, 1000, CTC_EVENT_TIMER, ch);
1030*4882a593Smuzhiyun 		if (event == CTC_EVENT_TIMER) /* for TIMER not yet locked */
1031*4882a593Smuzhiyun 			spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
1032*4882a593Smuzhiyun 			/* Such conditional locking is a known problem for
1033*4882a593Smuzhiyun 			 * sparse because its undeterministic in static view.
1034*4882a593Smuzhiyun 			 * Warnings should be ignored here. */
1035*4882a593Smuzhiyun 		if (do_debug_ccw)
1036*4882a593Smuzhiyun 			ctcmpc_dumpit((char *)&ch->ccw[3],
1037*4882a593Smuzhiyun 					sizeof(struct ccw1) * 3);
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 		rc = ccw_device_start(ch->cdev, &ch->ccw[3], 0, 0xff, 0);
1040*4882a593Smuzhiyun 		if (event == CTC_EVENT_TIMER)
1041*4882a593Smuzhiyun 			spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev),
1042*4882a593Smuzhiyun 					saveflags);
1043*4882a593Smuzhiyun 		if (rc != 0) {
1044*4882a593Smuzhiyun 			fsm_deltimer(&ch->timer);
1045*4882a593Smuzhiyun 			ctcm_ccw_check_rc(ch, rc, "TX in chx_txretry");
1046*4882a593Smuzhiyun 			ctcm_purge_skb_queue(&ch->io_queue);
1047*4882a593Smuzhiyun 		}
1048*4882a593Smuzhiyun 	}
1049*4882a593Smuzhiyun done:
1050*4882a593Smuzhiyun 	return;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun /**
1054*4882a593Smuzhiyun  * Handle fatal errors during an I/O command.
1055*4882a593Smuzhiyun  *
1056*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
1057*4882a593Smuzhiyun  * event	The event, just happened.
1058*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
1059*4882a593Smuzhiyun  */
ctcm_chx_iofatal(fsm_instance * fi,int event,void * arg)1060*4882a593Smuzhiyun static void ctcm_chx_iofatal(fsm_instance *fi, int event, void *arg)
1061*4882a593Smuzhiyun {
1062*4882a593Smuzhiyun 	struct channel *ch = arg;
1063*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
1064*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
1065*4882a593Smuzhiyun 	int rd = CHANNEL_DIRECTION(ch->flags);
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
1068*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
1069*4882a593Smuzhiyun 		"%s: %s: %s unrecoverable channel error",
1070*4882a593Smuzhiyun 			CTCM_FUNTAIL, ch->id, rd == CTCM_READ ? "RX" : "TX");
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	if (IS_MPC(ch)) {
1073*4882a593Smuzhiyun 		priv->stats.tx_dropped++;
1074*4882a593Smuzhiyun 		priv->stats.tx_errors++;
1075*4882a593Smuzhiyun 	}
1076*4882a593Smuzhiyun 	if (rd == CTCM_READ) {
1077*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_RXERR);
1078*4882a593Smuzhiyun 		fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev);
1079*4882a593Smuzhiyun 	} else {
1080*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_TXERR);
1081*4882a593Smuzhiyun 		fsm_event(priv->fsm, DEV_EVENT_TXDOWN, dev);
1082*4882a593Smuzhiyun 	}
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun /*
1086*4882a593Smuzhiyun  * The ctcm statemachine for a channel.
1087*4882a593Smuzhiyun  */
1088*4882a593Smuzhiyun const fsm_node ch_fsm[] = {
1089*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_STOP,		ctcm_action_nop  },
1090*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_START,	ctcm_chx_start  },
1091*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_FINSTAT,	ctcm_action_nop  },
1092*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_MC_FAIL,	ctcm_action_nop  },
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_STOP,		ctcm_chx_stop  },
1095*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_START,	ctcm_action_nop  },
1096*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_FINSTAT,	ctcm_action_nop  },
1097*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_MC_FAIL,	ctcm_action_nop  },
1098*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_MC_GOOD,	ctcm_chx_start  },
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1101*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_START,	ctcm_action_nop  },
1102*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_FINSTAT,	ctcm_chx_setmode  },
1103*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_TIMER,	ctcm_chx_setuperr  },
1104*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1105*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1108*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_TIMER,	ctcm_chx_setmode  },
1109*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_FINSTAT,	ctcm_action_nop  },
1110*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1113*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_START,	ctcm_action_nop  },
1114*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_FINSTAT,	chx_firstio  },
1115*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr  },
1116*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1117*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_TIMER,	ctcm_chx_setmode  },
1118*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1119*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1122*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_START,	ctcm_action_nop  },
1123*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_FINSTAT,	chx_rxidle  },
1124*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_UC_RCRESET,	ctcm_chx_rxiniterr  },
1125*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_UC_RSRESET,	ctcm_chx_rxiniterr  },
1126*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_TIMER,	ctcm_chx_rxiniterr  },
1127*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_ATTNBUSY,	ctcm_chx_rxinitfail  },
1128*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1129*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_UC_ZERO,	chx_firstio  },
1130*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1133*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_START,	ctcm_action_nop  },
1134*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_FINSTAT,	chx_rx  },
1135*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_UC_RCRESET,	ctcm_chx_rxdisc  },
1136*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1137*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1138*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_UC_ZERO,	chx_rx  },
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1141*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_START,	ctcm_action_nop  },
1142*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_FINSTAT,	ctcm_chx_txidle  },
1143*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_UC_RCRESET,	ctcm_chx_txiniterr  },
1144*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_UC_RSRESET,	ctcm_chx_txiniterr  },
1145*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_TIMER,	ctcm_chx_txiniterr  },
1146*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1147*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1150*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_START,	ctcm_action_nop  },
1151*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_FINSTAT,	chx_firstio  },
1152*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_UC_RCRESET,	ctcm_action_nop  },
1153*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_UC_RSRESET,	ctcm_action_nop  },
1154*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1155*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_STOP,		ctcm_action_nop  },
1158*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_START,	ctcm_chx_restart  },
1159*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_FINSTAT,	ctcm_chx_stopped  },
1160*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_UC_RCRESET,	ctcm_action_nop  },
1161*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_UC_RSRESET,	ctcm_action_nop  },
1162*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1165*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_START,	ctcm_chx_restart  },
1166*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_FINSTAT,	ctcm_chx_setmode  },
1167*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_UC_RCRESET,	ctcm_action_nop  },
1168*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_UC_RSRESET,	ctcm_action_nop  },
1169*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_STOP,		ctcm_chx_haltio  },
1172*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_START,	ctcm_action_nop  },
1173*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_FINSTAT,	chx_txdone  },
1174*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_UC_RCRESET,	ctcm_chx_txretry  },
1175*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_UC_RSRESET,	ctcm_chx_txretry  },
1176*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_TIMER,	ctcm_chx_txretry  },
1177*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1178*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	{ CTC_STATE_RXERR,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1181*4882a593Smuzhiyun 	{ CTC_STATE_TXERR,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1182*4882a593Smuzhiyun 	{ CTC_STATE_TXERR,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1183*4882a593Smuzhiyun 	{ CTC_STATE_RXERR,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1184*4882a593Smuzhiyun };
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun int ch_fsm_len = ARRAY_SIZE(ch_fsm);
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun /*
1189*4882a593Smuzhiyun  * MPC actions for mpc channel statemachine
1190*4882a593Smuzhiyun  * handling of MPC protocol requires extra
1191*4882a593Smuzhiyun  * statemachine and actions which are prefixed ctcmpc_ .
1192*4882a593Smuzhiyun  * The ctc_ch_states and ctc_ch_state_names,
1193*4882a593Smuzhiyun  * ctc_ch_events and ctc_ch_event_names share the ctcm definitions
1194*4882a593Smuzhiyun  * which are expanded by some elements.
1195*4882a593Smuzhiyun  */
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun /*
1198*4882a593Smuzhiyun  * Actions for mpc channel statemachine.
1199*4882a593Smuzhiyun  */
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun /**
1202*4882a593Smuzhiyun  * Normal data has been send. Free the corresponding
1203*4882a593Smuzhiyun  * skb (it's in io_queue), reset dev->tbusy and
1204*4882a593Smuzhiyun  * revert to idle state.
1205*4882a593Smuzhiyun  *
1206*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
1207*4882a593Smuzhiyun  * event	The event, just happened.
1208*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
1209*4882a593Smuzhiyun  */
ctcmpc_chx_txdone(fsm_instance * fi,int event,void * arg)1210*4882a593Smuzhiyun static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
1211*4882a593Smuzhiyun {
1212*4882a593Smuzhiyun 	struct channel		*ch = arg;
1213*4882a593Smuzhiyun 	struct net_device	*dev = ch->netdev;
1214*4882a593Smuzhiyun 	struct ctcm_priv	*priv = dev->ml_priv;
1215*4882a593Smuzhiyun 	struct mpc_group	*grp = priv->mpcg;
1216*4882a593Smuzhiyun 	struct sk_buff		*skb;
1217*4882a593Smuzhiyun 	int		first = 1;
1218*4882a593Smuzhiyun 	int		i;
1219*4882a593Smuzhiyun 	__u32		data_space;
1220*4882a593Smuzhiyun 	unsigned long	duration;
1221*4882a593Smuzhiyun 	struct sk_buff	*peekskb;
1222*4882a593Smuzhiyun 	int		rc;
1223*4882a593Smuzhiyun 	struct th_header *header;
1224*4882a593Smuzhiyun 	struct pdu	*p_header;
1225*4882a593Smuzhiyun 	unsigned long done_stamp = jiffies;
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun 	CTCM_PR_DEBUG("Enter %s: %s cp:%i\n",
1228*4882a593Smuzhiyun 			__func__, dev->name, smp_processor_id());
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	duration = done_stamp - ch->prof.send_stamp;
1231*4882a593Smuzhiyun 	if (duration > ch->prof.tx_time)
1232*4882a593Smuzhiyun 		ch->prof.tx_time = duration;
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	if (ch->irb->scsw.cmd.count != 0)
1235*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_DEBUG,
1236*4882a593Smuzhiyun 			"%s(%s): TX not complete, remaining %d bytes",
1237*4882a593Smuzhiyun 			     CTCM_FUNTAIL, dev->name, ch->irb->scsw.cmd.count);
1238*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
1239*4882a593Smuzhiyun 	while ((skb = skb_dequeue(&ch->io_queue))) {
1240*4882a593Smuzhiyun 		priv->stats.tx_packets++;
1241*4882a593Smuzhiyun 		priv->stats.tx_bytes += skb->len - TH_HEADER_LENGTH;
1242*4882a593Smuzhiyun 		if (first) {
1243*4882a593Smuzhiyun 			priv->stats.tx_bytes += 2;
1244*4882a593Smuzhiyun 			first = 0;
1245*4882a593Smuzhiyun 		}
1246*4882a593Smuzhiyun 		refcount_dec(&skb->users);
1247*4882a593Smuzhiyun 		dev_kfree_skb_irq(skb);
1248*4882a593Smuzhiyun 	}
1249*4882a593Smuzhiyun 	spin_lock(&ch->collect_lock);
1250*4882a593Smuzhiyun 	clear_normalized_cda(&ch->ccw[4]);
1251*4882a593Smuzhiyun 	if ((ch->collect_len <= 0) || (grp->in_sweep != 0)) {
1252*4882a593Smuzhiyun 		spin_unlock(&ch->collect_lock);
1253*4882a593Smuzhiyun 		fsm_newstate(fi, CTC_STATE_TXIDLE);
1254*4882a593Smuzhiyun 				goto done;
1255*4882a593Smuzhiyun 	}
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	if (ctcm_checkalloc_buffer(ch)) {
1258*4882a593Smuzhiyun 		spin_unlock(&ch->collect_lock);
1259*4882a593Smuzhiyun 				goto done;
1260*4882a593Smuzhiyun 	}
1261*4882a593Smuzhiyun 	ch->trans_skb->data = ch->trans_skb_data;
1262*4882a593Smuzhiyun 	skb_reset_tail_pointer(ch->trans_skb);
1263*4882a593Smuzhiyun 	ch->trans_skb->len = 0;
1264*4882a593Smuzhiyun 	if (ch->prof.maxmulti < (ch->collect_len + TH_HEADER_LENGTH))
1265*4882a593Smuzhiyun 		ch->prof.maxmulti = ch->collect_len + TH_HEADER_LENGTH;
1266*4882a593Smuzhiyun 	if (ch->prof.maxcqueue < skb_queue_len(&ch->collect_queue))
1267*4882a593Smuzhiyun 		ch->prof.maxcqueue = skb_queue_len(&ch->collect_queue);
1268*4882a593Smuzhiyun 	i = 0;
1269*4882a593Smuzhiyun 	p_header = NULL;
1270*4882a593Smuzhiyun 	data_space = grp->group_max_buflen - TH_HEADER_LENGTH;
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("%s: building trans_skb from collect_q"
1273*4882a593Smuzhiyun 		       " data_space:%04x\n",
1274*4882a593Smuzhiyun 		       __func__, data_space);
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	while ((skb = skb_dequeue(&ch->collect_queue))) {
1277*4882a593Smuzhiyun 		skb_put_data(ch->trans_skb, skb->data, skb->len);
1278*4882a593Smuzhiyun 		p_header = (struct pdu *)
1279*4882a593Smuzhiyun 			(skb_tail_pointer(ch->trans_skb) - skb->len);
1280*4882a593Smuzhiyun 		p_header->pdu_flag = 0x00;
1281*4882a593Smuzhiyun 		if (be16_to_cpu(skb->protocol) == ETH_P_SNAP)
1282*4882a593Smuzhiyun 			p_header->pdu_flag |= 0x60;
1283*4882a593Smuzhiyun 		else
1284*4882a593Smuzhiyun 			p_header->pdu_flag |= 0x20;
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 		CTCM_PR_DBGDATA("%s: trans_skb len:%04x \n",
1287*4882a593Smuzhiyun 				__func__, ch->trans_skb->len);
1288*4882a593Smuzhiyun 		CTCM_PR_DBGDATA("%s: pdu header and data for up"
1289*4882a593Smuzhiyun 				" to 32 bytes sent to vtam\n", __func__);
1290*4882a593Smuzhiyun 		CTCM_D3_DUMP((char *)p_header, min_t(int, skb->len, 32));
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 		ch->collect_len -= skb->len;
1293*4882a593Smuzhiyun 		data_space -= skb->len;
1294*4882a593Smuzhiyun 		priv->stats.tx_packets++;
1295*4882a593Smuzhiyun 		priv->stats.tx_bytes += skb->len;
1296*4882a593Smuzhiyun 		refcount_dec(&skb->users);
1297*4882a593Smuzhiyun 		dev_kfree_skb_any(skb);
1298*4882a593Smuzhiyun 		peekskb = skb_peek(&ch->collect_queue);
1299*4882a593Smuzhiyun 		if (peekskb->len > data_space)
1300*4882a593Smuzhiyun 			break;
1301*4882a593Smuzhiyun 		i++;
1302*4882a593Smuzhiyun 	}
1303*4882a593Smuzhiyun 	/* p_header points to the last one we handled */
1304*4882a593Smuzhiyun 	if (p_header)
1305*4882a593Smuzhiyun 		p_header->pdu_flag |= PDU_LAST;	/*Say it's the last one*/
1306*4882a593Smuzhiyun 	header = kzalloc(TH_HEADER_LENGTH, gfp_type());
1307*4882a593Smuzhiyun 	if (!header) {
1308*4882a593Smuzhiyun 		spin_unlock(&ch->collect_lock);
1309*4882a593Smuzhiyun 		fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
1310*4882a593Smuzhiyun 				goto done;
1311*4882a593Smuzhiyun 	}
1312*4882a593Smuzhiyun 	header->th_ch_flag = TH_HAS_PDU;  /* Normal data */
1313*4882a593Smuzhiyun 	ch->th_seq_num++;
1314*4882a593Smuzhiyun 	header->th_seq_num = ch->th_seq_num;
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("%s: ToVTAM_th_seq= %08x\n" ,
1317*4882a593Smuzhiyun 					__func__, ch->th_seq_num);
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 	memcpy(skb_push(ch->trans_skb, TH_HEADER_LENGTH), header,
1320*4882a593Smuzhiyun 		TH_HEADER_LENGTH);	/* put the TH on the packet */
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 	kfree(header);
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("%s: trans_skb len:%04x \n",
1325*4882a593Smuzhiyun 		       __func__, ch->trans_skb->len);
1326*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("%s: up-to-50 bytes of trans_skb "
1327*4882a593Smuzhiyun 			"data to vtam from collect_q\n", __func__);
1328*4882a593Smuzhiyun 	CTCM_D3_DUMP((char *)ch->trans_skb->data,
1329*4882a593Smuzhiyun 				min_t(int, ch->trans_skb->len, 50));
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 	spin_unlock(&ch->collect_lock);
1332*4882a593Smuzhiyun 	clear_normalized_cda(&ch->ccw[1]);
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
1335*4882a593Smuzhiyun 			(void *)(unsigned long)ch->ccw[1].cda,
1336*4882a593Smuzhiyun 			ch->trans_skb->data);
1337*4882a593Smuzhiyun 	ch->ccw[1].count = ch->max_bufsize;
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun 	if (set_normalized_cda(&ch->ccw[1], ch->trans_skb->data)) {
1340*4882a593Smuzhiyun 		dev_kfree_skb_any(ch->trans_skb);
1341*4882a593Smuzhiyun 		ch->trans_skb = NULL;
1342*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_ERROR,
1343*4882a593Smuzhiyun 			"%s: %s: IDAL alloc failed",
1344*4882a593Smuzhiyun 				CTCM_FUNTAIL, ch->id);
1345*4882a593Smuzhiyun 		fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
1346*4882a593Smuzhiyun 		return;
1347*4882a593Smuzhiyun 	}
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
1350*4882a593Smuzhiyun 			(void *)(unsigned long)ch->ccw[1].cda,
1351*4882a593Smuzhiyun 			ch->trans_skb->data);
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 	ch->ccw[1].count = ch->trans_skb->len;
1354*4882a593Smuzhiyun 	fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
1355*4882a593Smuzhiyun 	ch->prof.send_stamp = jiffies;
1356*4882a593Smuzhiyun 	if (do_debug_ccw)
1357*4882a593Smuzhiyun 		ctcmpc_dumpit((char *)&ch->ccw[0], sizeof(struct ccw1) * 3);
1358*4882a593Smuzhiyun 	rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
1359*4882a593Smuzhiyun 	ch->prof.doios_multi++;
1360*4882a593Smuzhiyun 	if (rc != 0) {
1361*4882a593Smuzhiyun 		priv->stats.tx_dropped += i;
1362*4882a593Smuzhiyun 		priv->stats.tx_errors += i;
1363*4882a593Smuzhiyun 		fsm_deltimer(&ch->timer);
1364*4882a593Smuzhiyun 		ctcm_ccw_check_rc(ch, rc, "chained TX");
1365*4882a593Smuzhiyun 	}
1366*4882a593Smuzhiyun done:
1367*4882a593Smuzhiyun 	ctcm_clear_busy(dev);
1368*4882a593Smuzhiyun 	return;
1369*4882a593Smuzhiyun }
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun /**
1372*4882a593Smuzhiyun  * Got normal data, check for sanity, queue it up, allocate new buffer
1373*4882a593Smuzhiyun  * trigger bottom half, and initiate next read.
1374*4882a593Smuzhiyun  *
1375*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
1376*4882a593Smuzhiyun  * event	The event, just happened.
1377*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
1378*4882a593Smuzhiyun  */
ctcmpc_chx_rx(fsm_instance * fi,int event,void * arg)1379*4882a593Smuzhiyun static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg)
1380*4882a593Smuzhiyun {
1381*4882a593Smuzhiyun 	struct channel		*ch = arg;
1382*4882a593Smuzhiyun 	struct net_device	*dev = ch->netdev;
1383*4882a593Smuzhiyun 	struct ctcm_priv	*priv = dev->ml_priv;
1384*4882a593Smuzhiyun 	struct mpc_group	*grp = priv->mpcg;
1385*4882a593Smuzhiyun 	struct sk_buff		*skb = ch->trans_skb;
1386*4882a593Smuzhiyun 	struct sk_buff		*new_skb;
1387*4882a593Smuzhiyun 	unsigned long		saveflags = 0;	/* avoids compiler warning */
1388*4882a593Smuzhiyun 	int len	= ch->max_bufsize - ch->irb->scsw.cmd.count;
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	CTCM_PR_DEBUG("%s: %s: cp:%i %s maxbuf : %04x, len: %04x\n",
1391*4882a593Smuzhiyun 			CTCM_FUNTAIL, dev->name, smp_processor_id(),
1392*4882a593Smuzhiyun 				ch->id, ch->max_bufsize, len);
1393*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 	if (skb == NULL) {
1396*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
1397*4882a593Smuzhiyun 			"%s(%s): TRANS_SKB = NULL",
1398*4882a593Smuzhiyun 				CTCM_FUNTAIL, dev->name);
1399*4882a593Smuzhiyun 			goto again;
1400*4882a593Smuzhiyun 	}
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 	if (len < TH_HEADER_LENGTH) {
1403*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
1404*4882a593Smuzhiyun 				"%s(%s): packet length %d to short",
1405*4882a593Smuzhiyun 					CTCM_FUNTAIL, dev->name, len);
1406*4882a593Smuzhiyun 		priv->stats.rx_dropped++;
1407*4882a593Smuzhiyun 		priv->stats.rx_length_errors++;
1408*4882a593Smuzhiyun 	} else {
1409*4882a593Smuzhiyun 		/* must have valid th header or game over */
1410*4882a593Smuzhiyun 		__u32	block_len = len;
1411*4882a593Smuzhiyun 		len = TH_HEADER_LENGTH + XID2_LENGTH + 4;
1412*4882a593Smuzhiyun 		new_skb = __dev_alloc_skb(ch->max_bufsize, GFP_ATOMIC);
1413*4882a593Smuzhiyun 
1414*4882a593Smuzhiyun 		if (new_skb == NULL) {
1415*4882a593Smuzhiyun 			CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
1416*4882a593Smuzhiyun 				"%s(%d): skb allocation failed",
1417*4882a593Smuzhiyun 						CTCM_FUNTAIL, dev->name);
1418*4882a593Smuzhiyun 			fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
1419*4882a593Smuzhiyun 					goto again;
1420*4882a593Smuzhiyun 		}
1421*4882a593Smuzhiyun 		switch (fsm_getstate(grp->fsm)) {
1422*4882a593Smuzhiyun 		case MPCG_STATE_RESET:
1423*4882a593Smuzhiyun 		case MPCG_STATE_INOP:
1424*4882a593Smuzhiyun 			dev_kfree_skb_any(new_skb);
1425*4882a593Smuzhiyun 			break;
1426*4882a593Smuzhiyun 		case MPCG_STATE_FLOWC:
1427*4882a593Smuzhiyun 		case MPCG_STATE_READY:
1428*4882a593Smuzhiyun 			skb_put_data(new_skb, skb->data, block_len);
1429*4882a593Smuzhiyun 			skb_queue_tail(&ch->io_queue, new_skb);
1430*4882a593Smuzhiyun 			tasklet_schedule(&ch->ch_tasklet);
1431*4882a593Smuzhiyun 			break;
1432*4882a593Smuzhiyun 		default:
1433*4882a593Smuzhiyun 			skb_put_data(new_skb, skb->data, len);
1434*4882a593Smuzhiyun 			skb_queue_tail(&ch->io_queue, new_skb);
1435*4882a593Smuzhiyun 			tasklet_hi_schedule(&ch->ch_tasklet);
1436*4882a593Smuzhiyun 			break;
1437*4882a593Smuzhiyun 		}
1438*4882a593Smuzhiyun 	}
1439*4882a593Smuzhiyun 
1440*4882a593Smuzhiyun again:
1441*4882a593Smuzhiyun 	switch (fsm_getstate(grp->fsm)) {
1442*4882a593Smuzhiyun 	int rc, dolock;
1443*4882a593Smuzhiyun 	case MPCG_STATE_FLOWC:
1444*4882a593Smuzhiyun 	case MPCG_STATE_READY:
1445*4882a593Smuzhiyun 		if (ctcm_checkalloc_buffer(ch))
1446*4882a593Smuzhiyun 			break;
1447*4882a593Smuzhiyun 		ch->trans_skb->data = ch->trans_skb_data;
1448*4882a593Smuzhiyun 		skb_reset_tail_pointer(ch->trans_skb);
1449*4882a593Smuzhiyun 		ch->trans_skb->len = 0;
1450*4882a593Smuzhiyun 		ch->ccw[1].count = ch->max_bufsize;
1451*4882a593Smuzhiyun 			if (do_debug_ccw)
1452*4882a593Smuzhiyun 			ctcmpc_dumpit((char *)&ch->ccw[0],
1453*4882a593Smuzhiyun 					sizeof(struct ccw1) * 3);
1454*4882a593Smuzhiyun 		dolock = !in_irq();
1455*4882a593Smuzhiyun 		if (dolock)
1456*4882a593Smuzhiyun 			spin_lock_irqsave(
1457*4882a593Smuzhiyun 				get_ccwdev_lock(ch->cdev), saveflags);
1458*4882a593Smuzhiyun 		rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
1459*4882a593Smuzhiyun 		if (dolock) /* see remark about conditional locking */
1460*4882a593Smuzhiyun 			spin_unlock_irqrestore(
1461*4882a593Smuzhiyun 				get_ccwdev_lock(ch->cdev), saveflags);
1462*4882a593Smuzhiyun 		if (rc != 0)
1463*4882a593Smuzhiyun 			ctcm_ccw_check_rc(ch, rc, "normal RX");
1464*4882a593Smuzhiyun 	default:
1465*4882a593Smuzhiyun 		break;
1466*4882a593Smuzhiyun 	}
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun 	CTCM_PR_DEBUG("Exit %s: %s, ch=0x%p, id=%s\n",
1469*4882a593Smuzhiyun 			__func__, dev->name, ch, ch->id);
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun }
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun /**
1474*4882a593Smuzhiyun  * Initialize connection by sending a __u16 of value 0.
1475*4882a593Smuzhiyun  *
1476*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
1477*4882a593Smuzhiyun  * event	The event, just happened.
1478*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
1479*4882a593Smuzhiyun  */
ctcmpc_chx_firstio(fsm_instance * fi,int event,void * arg)1480*4882a593Smuzhiyun static void ctcmpc_chx_firstio(fsm_instance *fi, int event, void *arg)
1481*4882a593Smuzhiyun {
1482*4882a593Smuzhiyun 	struct channel		*ch = arg;
1483*4882a593Smuzhiyun 	struct net_device	*dev = ch->netdev;
1484*4882a593Smuzhiyun 	struct ctcm_priv	*priv = dev->ml_priv;
1485*4882a593Smuzhiyun 	struct mpc_group	*gptr = priv->mpcg;
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun 	CTCM_PR_DEBUG("Enter %s: id=%s, ch=0x%p\n",
1488*4882a593Smuzhiyun 				__func__, ch->id, ch);
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_INFO,
1491*4882a593Smuzhiyun 			"%s: %s: chstate:%i, grpstate:%i, prot:%i\n",
1492*4882a593Smuzhiyun 			CTCM_FUNTAIL, ch->id, fsm_getstate(fi),
1493*4882a593Smuzhiyun 			fsm_getstate(gptr->fsm), ch->protocol);
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 	if (fsm_getstate(fi) == CTC_STATE_TXIDLE)
1496*4882a593Smuzhiyun 		MPC_DBF_DEV_NAME(TRACE, dev, "remote side issued READ? ");
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
1499*4882a593Smuzhiyun 	if (ctcm_checkalloc_buffer(ch))
1500*4882a593Smuzhiyun 				goto done;
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	switch (fsm_getstate(fi)) {
1503*4882a593Smuzhiyun 	case CTC_STATE_STARTRETRY:
1504*4882a593Smuzhiyun 	case CTC_STATE_SETUPWAIT:
1505*4882a593Smuzhiyun 		if (CHANNEL_DIRECTION(ch->flags) == CTCM_READ) {
1506*4882a593Smuzhiyun 			ctcmpc_chx_rxidle(fi, event, arg);
1507*4882a593Smuzhiyun 		} else {
1508*4882a593Smuzhiyun 			fsm_newstate(fi, CTC_STATE_TXIDLE);
1509*4882a593Smuzhiyun 			fsm_event(priv->fsm, DEV_EVENT_TXUP, dev);
1510*4882a593Smuzhiyun 		}
1511*4882a593Smuzhiyun 				goto done;
1512*4882a593Smuzhiyun 	default:
1513*4882a593Smuzhiyun 		break;
1514*4882a593Smuzhiyun 	}
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun 	fsm_newstate(fi, (CHANNEL_DIRECTION(ch->flags) == CTCM_READ)
1517*4882a593Smuzhiyun 		     ? CTC_STATE_RXINIT : CTC_STATE_TXINIT);
1518*4882a593Smuzhiyun 
1519*4882a593Smuzhiyun done:
1520*4882a593Smuzhiyun 	CTCM_PR_DEBUG("Exit %s: id=%s, ch=0x%p\n",
1521*4882a593Smuzhiyun 				__func__, ch->id, ch);
1522*4882a593Smuzhiyun 	return;
1523*4882a593Smuzhiyun }
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun /**
1526*4882a593Smuzhiyun  * Got initial data, check it. If OK,
1527*4882a593Smuzhiyun  * notify device statemachine that we are up and
1528*4882a593Smuzhiyun  * running.
1529*4882a593Smuzhiyun  *
1530*4882a593Smuzhiyun  * fi		An instance of a channel statemachine.
1531*4882a593Smuzhiyun  * event	The event, just happened.
1532*4882a593Smuzhiyun  * arg		Generic pointer, casted from channel * upon call.
1533*4882a593Smuzhiyun  */
ctcmpc_chx_rxidle(fsm_instance * fi,int event,void * arg)1534*4882a593Smuzhiyun void ctcmpc_chx_rxidle(fsm_instance *fi, int event, void *arg)
1535*4882a593Smuzhiyun {
1536*4882a593Smuzhiyun 	struct channel *ch = arg;
1537*4882a593Smuzhiyun 	struct net_device *dev = ch->netdev;
1538*4882a593Smuzhiyun 	struct ctcm_priv  *priv = dev->ml_priv;
1539*4882a593Smuzhiyun 	struct mpc_group  *grp = priv->mpcg;
1540*4882a593Smuzhiyun 	int rc;
1541*4882a593Smuzhiyun 	unsigned long saveflags = 0;	/* avoids compiler warning */
1542*4882a593Smuzhiyun 
1543*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
1544*4882a593Smuzhiyun 	CTCM_PR_DEBUG("%s: %s: %s: cp:%i, chstate:%i grpstate:%i\n",
1545*4882a593Smuzhiyun 			__func__, ch->id, dev->name, smp_processor_id(),
1546*4882a593Smuzhiyun 				fsm_getstate(fi), fsm_getstate(grp->fsm));
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun 	fsm_newstate(fi, CTC_STATE_RXIDLE);
1549*4882a593Smuzhiyun 	/* XID processing complete */
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 	switch (fsm_getstate(grp->fsm)) {
1552*4882a593Smuzhiyun 	case MPCG_STATE_FLOWC:
1553*4882a593Smuzhiyun 	case MPCG_STATE_READY:
1554*4882a593Smuzhiyun 		if (ctcm_checkalloc_buffer(ch))
1555*4882a593Smuzhiyun 				goto done;
1556*4882a593Smuzhiyun 		ch->trans_skb->data = ch->trans_skb_data;
1557*4882a593Smuzhiyun 		skb_reset_tail_pointer(ch->trans_skb);
1558*4882a593Smuzhiyun 		ch->trans_skb->len = 0;
1559*4882a593Smuzhiyun 		ch->ccw[1].count = ch->max_bufsize;
1560*4882a593Smuzhiyun 		CTCM_CCW_DUMP((char *)&ch->ccw[0], sizeof(struct ccw1) * 3);
1561*4882a593Smuzhiyun 		if (event == CTC_EVENT_START)
1562*4882a593Smuzhiyun 			/* see remark about conditional locking */
1563*4882a593Smuzhiyun 			spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
1564*4882a593Smuzhiyun 		rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
1565*4882a593Smuzhiyun 		if (event == CTC_EVENT_START)
1566*4882a593Smuzhiyun 			spin_unlock_irqrestore(
1567*4882a593Smuzhiyun 					get_ccwdev_lock(ch->cdev), saveflags);
1568*4882a593Smuzhiyun 		if (rc != 0) {
1569*4882a593Smuzhiyun 			fsm_newstate(fi, CTC_STATE_RXINIT);
1570*4882a593Smuzhiyun 			ctcm_ccw_check_rc(ch, rc, "initial RX");
1571*4882a593Smuzhiyun 				goto done;
1572*4882a593Smuzhiyun 		}
1573*4882a593Smuzhiyun 		break;
1574*4882a593Smuzhiyun 	default:
1575*4882a593Smuzhiyun 		break;
1576*4882a593Smuzhiyun 	}
1577*4882a593Smuzhiyun 
1578*4882a593Smuzhiyun 	fsm_event(priv->fsm, DEV_EVENT_RXUP, dev);
1579*4882a593Smuzhiyun done:
1580*4882a593Smuzhiyun 	return;
1581*4882a593Smuzhiyun }
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun /*
1584*4882a593Smuzhiyun  * ctcmpc channel FSM action
1585*4882a593Smuzhiyun  * called from several points in ctcmpc_ch_fsm
1586*4882a593Smuzhiyun  * ctcmpc only
1587*4882a593Smuzhiyun  */
ctcmpc_chx_attn(fsm_instance * fsm,int event,void * arg)1588*4882a593Smuzhiyun static void ctcmpc_chx_attn(fsm_instance *fsm, int event, void *arg)
1589*4882a593Smuzhiyun {
1590*4882a593Smuzhiyun 	struct channel	  *ch     = arg;
1591*4882a593Smuzhiyun 	struct net_device *dev    = ch->netdev;
1592*4882a593Smuzhiyun 	struct ctcm_priv  *priv   = dev->ml_priv;
1593*4882a593Smuzhiyun 	struct mpc_group  *grp = priv->mpcg;
1594*4882a593Smuzhiyun 
1595*4882a593Smuzhiyun 	CTCM_PR_DEBUG("%s(%s): %s(ch=0x%p), cp=%i, ChStat:%s, GrpStat:%s\n",
1596*4882a593Smuzhiyun 		__func__, dev->name, ch->id, ch, smp_processor_id(),
1597*4882a593Smuzhiyun 			fsm_getstate_str(ch->fsm), fsm_getstate_str(grp->fsm));
1598*4882a593Smuzhiyun 
1599*4882a593Smuzhiyun 	switch (fsm_getstate(grp->fsm)) {
1600*4882a593Smuzhiyun 	case MPCG_STATE_XID2INITW:
1601*4882a593Smuzhiyun 		/* ok..start yside xid exchanges */
1602*4882a593Smuzhiyun 		if (!ch->in_mpcgroup)
1603*4882a593Smuzhiyun 			break;
1604*4882a593Smuzhiyun 		if (fsm_getstate(ch->fsm) ==  CH_XID0_PENDING) {
1605*4882a593Smuzhiyun 			fsm_deltimer(&grp->timer);
1606*4882a593Smuzhiyun 			fsm_addtimer(&grp->timer,
1607*4882a593Smuzhiyun 				MPC_XID_TIMEOUT_VALUE,
1608*4882a593Smuzhiyun 				MPCG_EVENT_TIMER, dev);
1609*4882a593Smuzhiyun 			fsm_event(grp->fsm, MPCG_EVENT_XID0DO, ch);
1610*4882a593Smuzhiyun 
1611*4882a593Smuzhiyun 		} else if (fsm_getstate(ch->fsm) < CH_XID7_PENDING1)
1612*4882a593Smuzhiyun 			/* attn rcvd before xid0 processed via bh */
1613*4882a593Smuzhiyun 			fsm_newstate(ch->fsm, CH_XID7_PENDING1);
1614*4882a593Smuzhiyun 		break;
1615*4882a593Smuzhiyun 	case MPCG_STATE_XID2INITX:
1616*4882a593Smuzhiyun 	case MPCG_STATE_XID0IOWAIT:
1617*4882a593Smuzhiyun 	case MPCG_STATE_XID0IOWAIX:
1618*4882a593Smuzhiyun 		/* attn rcvd before xid0 processed on ch
1619*4882a593Smuzhiyun 		but mid-xid0 processing for group    */
1620*4882a593Smuzhiyun 		if (fsm_getstate(ch->fsm) < CH_XID7_PENDING1)
1621*4882a593Smuzhiyun 			fsm_newstate(ch->fsm, CH_XID7_PENDING1);
1622*4882a593Smuzhiyun 		break;
1623*4882a593Smuzhiyun 	case MPCG_STATE_XID7INITW:
1624*4882a593Smuzhiyun 	case MPCG_STATE_XID7INITX:
1625*4882a593Smuzhiyun 	case MPCG_STATE_XID7INITI:
1626*4882a593Smuzhiyun 	case MPCG_STATE_XID7INITZ:
1627*4882a593Smuzhiyun 		switch (fsm_getstate(ch->fsm)) {
1628*4882a593Smuzhiyun 		case CH_XID7_PENDING:
1629*4882a593Smuzhiyun 			fsm_newstate(ch->fsm, CH_XID7_PENDING1);
1630*4882a593Smuzhiyun 			break;
1631*4882a593Smuzhiyun 		case CH_XID7_PENDING2:
1632*4882a593Smuzhiyun 			fsm_newstate(ch->fsm, CH_XID7_PENDING3);
1633*4882a593Smuzhiyun 			break;
1634*4882a593Smuzhiyun 		}
1635*4882a593Smuzhiyun 		fsm_event(grp->fsm, MPCG_EVENT_XID7DONE, dev);
1636*4882a593Smuzhiyun 		break;
1637*4882a593Smuzhiyun 	}
1638*4882a593Smuzhiyun 
1639*4882a593Smuzhiyun 	return;
1640*4882a593Smuzhiyun }
1641*4882a593Smuzhiyun 
1642*4882a593Smuzhiyun /*
1643*4882a593Smuzhiyun  * ctcmpc channel FSM action
1644*4882a593Smuzhiyun  * called from one point in ctcmpc_ch_fsm
1645*4882a593Smuzhiyun  * ctcmpc only
1646*4882a593Smuzhiyun  */
ctcmpc_chx_attnbusy(fsm_instance * fsm,int event,void * arg)1647*4882a593Smuzhiyun static void ctcmpc_chx_attnbusy(fsm_instance *fsm, int event, void *arg)
1648*4882a593Smuzhiyun {
1649*4882a593Smuzhiyun 	struct channel	  *ch     = arg;
1650*4882a593Smuzhiyun 	struct net_device *dev    = ch->netdev;
1651*4882a593Smuzhiyun 	struct ctcm_priv  *priv   = dev->ml_priv;
1652*4882a593Smuzhiyun 	struct mpc_group  *grp    = priv->mpcg;
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	CTCM_PR_DEBUG("%s(%s): %s\n  ChState:%s GrpState:%s\n",
1655*4882a593Smuzhiyun 			__func__, dev->name, ch->id,
1656*4882a593Smuzhiyun 			fsm_getstate_str(ch->fsm), fsm_getstate_str(grp->fsm));
1657*4882a593Smuzhiyun 
1658*4882a593Smuzhiyun 	fsm_deltimer(&ch->timer);
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 	switch (fsm_getstate(grp->fsm)) {
1661*4882a593Smuzhiyun 	case MPCG_STATE_XID0IOWAIT:
1662*4882a593Smuzhiyun 		/* vtam wants to be primary.start yside xid exchanges*/
1663*4882a593Smuzhiyun 		/* only receive one attn-busy at a time so must not  */
1664*4882a593Smuzhiyun 		/* change state each time			     */
1665*4882a593Smuzhiyun 		grp->changed_side = 1;
1666*4882a593Smuzhiyun 		fsm_newstate(grp->fsm, MPCG_STATE_XID2INITW);
1667*4882a593Smuzhiyun 		break;
1668*4882a593Smuzhiyun 	case MPCG_STATE_XID2INITW:
1669*4882a593Smuzhiyun 		if (grp->changed_side == 1) {
1670*4882a593Smuzhiyun 			grp->changed_side = 2;
1671*4882a593Smuzhiyun 			break;
1672*4882a593Smuzhiyun 		}
1673*4882a593Smuzhiyun 		/* process began via call to establish_conn	 */
1674*4882a593Smuzhiyun 		/* so must report failure instead of reverting	 */
1675*4882a593Smuzhiyun 		/* back to ready-for-xid passive state		 */
1676*4882a593Smuzhiyun 		if (grp->estconnfunc)
1677*4882a593Smuzhiyun 				goto done;
1678*4882a593Smuzhiyun 		/* this attnbusy is NOT the result of xside xid  */
1679*4882a593Smuzhiyun 		/* collisions so yside must have been triggered  */
1680*4882a593Smuzhiyun 		/* by an ATTN that was not intended to start XID */
1681*4882a593Smuzhiyun 		/* processing. Revert back to ready-for-xid and  */
1682*4882a593Smuzhiyun 		/* wait for ATTN interrupt to signal xid start	 */
1683*4882a593Smuzhiyun 		if (fsm_getstate(ch->fsm) == CH_XID0_INPROGRESS) {
1684*4882a593Smuzhiyun 			fsm_newstate(ch->fsm, CH_XID0_PENDING) ;
1685*4882a593Smuzhiyun 			fsm_deltimer(&grp->timer);
1686*4882a593Smuzhiyun 				goto done;
1687*4882a593Smuzhiyun 		}
1688*4882a593Smuzhiyun 		fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
1689*4882a593Smuzhiyun 				goto done;
1690*4882a593Smuzhiyun 	case MPCG_STATE_XID2INITX:
1691*4882a593Smuzhiyun 		/* XID2 was received before ATTN Busy for second
1692*4882a593Smuzhiyun 		   channel.Send yside xid for second channel.
1693*4882a593Smuzhiyun 		*/
1694*4882a593Smuzhiyun 		if (grp->changed_side == 1) {
1695*4882a593Smuzhiyun 			grp->changed_side = 2;
1696*4882a593Smuzhiyun 			break;
1697*4882a593Smuzhiyun 		}
1698*4882a593Smuzhiyun 		fallthrough;
1699*4882a593Smuzhiyun 	case MPCG_STATE_XID0IOWAIX:
1700*4882a593Smuzhiyun 	case MPCG_STATE_XID7INITW:
1701*4882a593Smuzhiyun 	case MPCG_STATE_XID7INITX:
1702*4882a593Smuzhiyun 	case MPCG_STATE_XID7INITI:
1703*4882a593Smuzhiyun 	case MPCG_STATE_XID7INITZ:
1704*4882a593Smuzhiyun 	default:
1705*4882a593Smuzhiyun 		/* multiple attn-busy indicates too out-of-sync      */
1706*4882a593Smuzhiyun 		/* and they are certainly not being received as part */
1707*4882a593Smuzhiyun 		/* of valid mpc group negotiations..		     */
1708*4882a593Smuzhiyun 		fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
1709*4882a593Smuzhiyun 				goto done;
1710*4882a593Smuzhiyun 	}
1711*4882a593Smuzhiyun 
1712*4882a593Smuzhiyun 	if (grp->changed_side == 1) {
1713*4882a593Smuzhiyun 		fsm_deltimer(&grp->timer);
1714*4882a593Smuzhiyun 		fsm_addtimer(&grp->timer, MPC_XID_TIMEOUT_VALUE,
1715*4882a593Smuzhiyun 			     MPCG_EVENT_TIMER, dev);
1716*4882a593Smuzhiyun 	}
1717*4882a593Smuzhiyun 	if (ch->in_mpcgroup)
1718*4882a593Smuzhiyun 		fsm_event(grp->fsm, MPCG_EVENT_XID0DO, ch);
1719*4882a593Smuzhiyun 	else
1720*4882a593Smuzhiyun 		CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
1721*4882a593Smuzhiyun 			"%s(%s): channel %s not added to group",
1722*4882a593Smuzhiyun 				CTCM_FUNTAIL, dev->name, ch->id);
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun done:
1725*4882a593Smuzhiyun 	return;
1726*4882a593Smuzhiyun }
1727*4882a593Smuzhiyun 
1728*4882a593Smuzhiyun /*
1729*4882a593Smuzhiyun  * ctcmpc channel FSM action
1730*4882a593Smuzhiyun  * called from several points in ctcmpc_ch_fsm
1731*4882a593Smuzhiyun  * ctcmpc only
1732*4882a593Smuzhiyun  */
ctcmpc_chx_resend(fsm_instance * fsm,int event,void * arg)1733*4882a593Smuzhiyun static void ctcmpc_chx_resend(fsm_instance *fsm, int event, void *arg)
1734*4882a593Smuzhiyun {
1735*4882a593Smuzhiyun 	struct channel	   *ch	   = arg;
1736*4882a593Smuzhiyun 	struct net_device  *dev    = ch->netdev;
1737*4882a593Smuzhiyun 	struct ctcm_priv   *priv   = dev->ml_priv;
1738*4882a593Smuzhiyun 	struct mpc_group   *grp    = priv->mpcg;
1739*4882a593Smuzhiyun 
1740*4882a593Smuzhiyun 	fsm_event(grp->fsm, MPCG_EVENT_XID0DO, ch);
1741*4882a593Smuzhiyun 	return;
1742*4882a593Smuzhiyun }
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun /*
1745*4882a593Smuzhiyun  * ctcmpc channel FSM action
1746*4882a593Smuzhiyun  * called from several points in ctcmpc_ch_fsm
1747*4882a593Smuzhiyun  * ctcmpc only
1748*4882a593Smuzhiyun  */
ctcmpc_chx_send_sweep(fsm_instance * fsm,int event,void * arg)1749*4882a593Smuzhiyun static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg)
1750*4882a593Smuzhiyun {
1751*4882a593Smuzhiyun 	struct channel *ach = arg;
1752*4882a593Smuzhiyun 	struct net_device *dev = ach->netdev;
1753*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
1754*4882a593Smuzhiyun 	struct mpc_group *grp = priv->mpcg;
1755*4882a593Smuzhiyun 	struct channel *wch = priv->channel[CTCM_WRITE];
1756*4882a593Smuzhiyun 	struct channel *rch = priv->channel[CTCM_READ];
1757*4882a593Smuzhiyun 	struct sk_buff *skb;
1758*4882a593Smuzhiyun 	struct th_sweep *header;
1759*4882a593Smuzhiyun 	int rc = 0;
1760*4882a593Smuzhiyun 	unsigned long saveflags = 0;
1761*4882a593Smuzhiyun 
1762*4882a593Smuzhiyun 	CTCM_PR_DEBUG("ctcmpc enter: %s(): cp=%i ch=0x%p id=%s\n",
1763*4882a593Smuzhiyun 			__func__, smp_processor_id(), ach, ach->id);
1764*4882a593Smuzhiyun 
1765*4882a593Smuzhiyun 	if (grp->in_sweep == 0)
1766*4882a593Smuzhiyun 				goto done;
1767*4882a593Smuzhiyun 
1768*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("%s: 1: ToVTAM_th_seq= %08x\n" ,
1769*4882a593Smuzhiyun 				__func__, wch->th_seq_num);
1770*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("%s: 1: FromVTAM_th_seq= %08x\n" ,
1771*4882a593Smuzhiyun 				__func__, rch->th_seq_num);
1772*4882a593Smuzhiyun 
1773*4882a593Smuzhiyun 	if (fsm_getstate(wch->fsm) != CTC_STATE_TXIDLE) {
1774*4882a593Smuzhiyun 		/* give the previous IO time to complete */
1775*4882a593Smuzhiyun 		fsm_addtimer(&wch->sweep_timer,
1776*4882a593Smuzhiyun 			200, CTC_EVENT_RSWEEP_TIMER, wch);
1777*4882a593Smuzhiyun 				goto done;
1778*4882a593Smuzhiyun 	}
1779*4882a593Smuzhiyun 
1780*4882a593Smuzhiyun 	skb = skb_dequeue(&wch->sweep_queue);
1781*4882a593Smuzhiyun 	if (!skb)
1782*4882a593Smuzhiyun 				goto done;
1783*4882a593Smuzhiyun 
1784*4882a593Smuzhiyun 	if (set_normalized_cda(&wch->ccw[4], skb->data)) {
1785*4882a593Smuzhiyun 		grp->in_sweep = 0;
1786*4882a593Smuzhiyun 		ctcm_clear_busy_do(dev);
1787*4882a593Smuzhiyun 		dev_kfree_skb_any(skb);
1788*4882a593Smuzhiyun 		fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
1789*4882a593Smuzhiyun 				goto done;
1790*4882a593Smuzhiyun 	} else {
1791*4882a593Smuzhiyun 		refcount_inc(&skb->users);
1792*4882a593Smuzhiyun 		skb_queue_tail(&wch->io_queue, skb);
1793*4882a593Smuzhiyun 	}
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	/* send out the sweep */
1796*4882a593Smuzhiyun 	wch->ccw[4].count = skb->len;
1797*4882a593Smuzhiyun 
1798*4882a593Smuzhiyun 	header = (struct th_sweep *)skb->data;
1799*4882a593Smuzhiyun 	switch (header->th.th_ch_flag) {
1800*4882a593Smuzhiyun 	case TH_SWEEP_REQ:
1801*4882a593Smuzhiyun 		grp->sweep_req_pend_num--;
1802*4882a593Smuzhiyun 		break;
1803*4882a593Smuzhiyun 	case TH_SWEEP_RESP:
1804*4882a593Smuzhiyun 		grp->sweep_rsp_pend_num--;
1805*4882a593Smuzhiyun 		break;
1806*4882a593Smuzhiyun 	}
1807*4882a593Smuzhiyun 
1808*4882a593Smuzhiyun 	header->sw.th_last_seq = wch->th_seq_num;
1809*4882a593Smuzhiyun 
1810*4882a593Smuzhiyun 	CTCM_CCW_DUMP((char *)&wch->ccw[3], sizeof(struct ccw1) * 3);
1811*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("%s: sweep packet\n", __func__);
1812*4882a593Smuzhiyun 	CTCM_D3_DUMP((char *)header, TH_SWEEP_LENGTH);
1813*4882a593Smuzhiyun 
1814*4882a593Smuzhiyun 	fsm_addtimer(&wch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, wch);
1815*4882a593Smuzhiyun 	fsm_newstate(wch->fsm, CTC_STATE_TX);
1816*4882a593Smuzhiyun 
1817*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(wch->cdev), saveflags);
1818*4882a593Smuzhiyun 	wch->prof.send_stamp = jiffies;
1819*4882a593Smuzhiyun 	rc = ccw_device_start(wch->cdev, &wch->ccw[3], 0, 0xff, 0);
1820*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(wch->cdev), saveflags);
1821*4882a593Smuzhiyun 
1822*4882a593Smuzhiyun 	if ((grp->sweep_req_pend_num == 0) &&
1823*4882a593Smuzhiyun 	   (grp->sweep_rsp_pend_num == 0)) {
1824*4882a593Smuzhiyun 		grp->in_sweep = 0;
1825*4882a593Smuzhiyun 		rch->th_seq_num = 0x00;
1826*4882a593Smuzhiyun 		wch->th_seq_num = 0x00;
1827*4882a593Smuzhiyun 		ctcm_clear_busy_do(dev);
1828*4882a593Smuzhiyun 	}
1829*4882a593Smuzhiyun 
1830*4882a593Smuzhiyun 	CTCM_PR_DBGDATA("%s: To-/From-VTAM_th_seq = %08x/%08x\n" ,
1831*4882a593Smuzhiyun 			__func__, wch->th_seq_num, rch->th_seq_num);
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun 	if (rc != 0)
1834*4882a593Smuzhiyun 		ctcm_ccw_check_rc(wch, rc, "send sweep");
1835*4882a593Smuzhiyun 
1836*4882a593Smuzhiyun done:
1837*4882a593Smuzhiyun 	return;
1838*4882a593Smuzhiyun }
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun 
1841*4882a593Smuzhiyun /*
1842*4882a593Smuzhiyun  * The ctcmpc statemachine for a channel.
1843*4882a593Smuzhiyun  */
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun const fsm_node ctcmpc_ch_fsm[] = {
1846*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_STOP,		ctcm_action_nop  },
1847*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_START,	ctcm_chx_start  },
1848*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1849*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_FINSTAT,	ctcm_action_nop  },
1850*4882a593Smuzhiyun 	{ CTC_STATE_STOPPED,	CTC_EVENT_MC_FAIL,	ctcm_action_nop  },
1851*4882a593Smuzhiyun 
1852*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_STOP,		ctcm_chx_stop  },
1853*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_START,	ctcm_action_nop  },
1854*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_FINSTAT,	ctcm_action_nop  },
1855*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_MC_FAIL,	ctcm_action_nop  },
1856*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_MC_GOOD,	ctcm_chx_start  },
1857*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_UC_RCRESET,	ctcm_chx_stop  },
1858*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_UC_RSRESET,	ctcm_chx_stop  },
1859*4882a593Smuzhiyun 	{ CTC_STATE_NOTOP,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1860*4882a593Smuzhiyun 
1861*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1862*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_START,	ctcm_action_nop  },
1863*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_FINSTAT,	ctcm_chx_setmode  },
1864*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_TIMER,	ctcm_chx_setuperr  },
1865*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1866*4882a593Smuzhiyun 	{ CTC_STATE_STARTWAIT,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1867*4882a593Smuzhiyun 
1868*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1869*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_TIMER,	ctcm_chx_setmode  },
1870*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_FINSTAT,	ctcm_chx_setmode  },
1871*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1872*4882a593Smuzhiyun 	{ CTC_STATE_STARTRETRY,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1875*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_START,	ctcm_action_nop  },
1876*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_FINSTAT,	ctcmpc_chx_firstio  },
1877*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr  },
1878*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1879*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_TIMER,	ctcm_chx_setmode  },
1880*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1881*4882a593Smuzhiyun 	{ CTC_STATE_SETUPWAIT,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1882*4882a593Smuzhiyun 
1883*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1884*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_START,	ctcm_action_nop  },
1885*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_FINSTAT,	ctcmpc_chx_rxidle  },
1886*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_UC_RCRESET,	ctcm_chx_rxiniterr  },
1887*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_UC_RSRESET,	ctcm_chx_rxiniterr  },
1888*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_TIMER,	ctcm_chx_rxiniterr  },
1889*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_ATTNBUSY,	ctcm_chx_rxinitfail  },
1890*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1891*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_UC_ZERO,	ctcmpc_chx_firstio  },
1892*4882a593Smuzhiyun 	{ CTC_STATE_RXINIT,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1893*4882a593Smuzhiyun 
1894*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_FINSTAT,	ctcm_action_nop  },
1895*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_ATTN,		ctcmpc_chx_attn  },
1896*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1897*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_START,	ctcm_action_nop  },
1898*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1899*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1900*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr  },
1901*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1902*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1903*4882a593Smuzhiyun 	{ CH_XID0_PENDING,	CTC_EVENT_ATTNBUSY,	ctcm_chx_iofatal  },
1904*4882a593Smuzhiyun 
1905*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_FINSTAT,	ctcmpc_chx_rx  },
1906*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_ATTN,		ctcmpc_chx_attn  },
1907*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1908*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_START,	ctcm_action_nop  },
1909*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1910*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1911*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_UC_ZERO,	ctcmpc_chx_rx  },
1912*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr },
1913*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_ATTNBUSY,	ctcmpc_chx_attnbusy  },
1914*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_TIMER,	ctcmpc_chx_resend  },
1915*4882a593Smuzhiyun 	{ CH_XID0_INPROGRESS,	CTC_EVENT_IO_EBUSY,	ctcm_chx_fail  },
1916*4882a593Smuzhiyun 
1917*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_FINSTAT,	ctcmpc_chx_rx  },
1918*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_ATTN,		ctcmpc_chx_attn  },
1919*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1920*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_START,	ctcm_action_nop  },
1921*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1922*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1923*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_UC_ZERO,	ctcmpc_chx_rx  },
1924*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr  },
1925*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1926*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1927*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_ATTNBUSY,	ctcm_chx_iofatal  },
1928*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_TIMER,	ctcmpc_chx_resend  },
1929*4882a593Smuzhiyun 	{ CH_XID7_PENDING,	CTC_EVENT_IO_EBUSY,	ctcm_chx_fail  },
1930*4882a593Smuzhiyun 
1931*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_FINSTAT,	ctcmpc_chx_rx  },
1932*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_ATTN,		ctcmpc_chx_attn  },
1933*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1934*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_START,	ctcm_action_nop  },
1935*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1936*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1937*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_UC_ZERO,	ctcmpc_chx_rx  },
1938*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr  },
1939*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1940*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_ATTNBUSY,	ctcm_chx_iofatal  },
1941*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_TIMER,	ctcmpc_chx_resend  },
1942*4882a593Smuzhiyun 	{ CH_XID7_PENDING1,	CTC_EVENT_IO_EBUSY,	ctcm_chx_fail  },
1943*4882a593Smuzhiyun 
1944*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_FINSTAT,	ctcmpc_chx_rx  },
1945*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_ATTN,		ctcmpc_chx_attn  },
1946*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1947*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_START,	ctcm_action_nop  },
1948*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1949*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1950*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_UC_ZERO,	ctcmpc_chx_rx  },
1951*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr  },
1952*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1953*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_ATTNBUSY,	ctcm_chx_iofatal  },
1954*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_TIMER,	ctcmpc_chx_resend  },
1955*4882a593Smuzhiyun 	{ CH_XID7_PENDING2,	CTC_EVENT_IO_EBUSY,	ctcm_chx_fail  },
1956*4882a593Smuzhiyun 
1957*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_FINSTAT,	ctcmpc_chx_rx  },
1958*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_ATTN,		ctcmpc_chx_attn  },
1959*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1960*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_START,	ctcm_action_nop  },
1961*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1962*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1963*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_UC_ZERO,	ctcmpc_chx_rx  },
1964*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr  },
1965*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1966*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_ATTNBUSY,	ctcm_chx_iofatal  },
1967*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_TIMER,	ctcmpc_chx_resend  },
1968*4882a593Smuzhiyun 	{ CH_XID7_PENDING3,	CTC_EVENT_IO_EBUSY,	ctcm_chx_fail  },
1969*4882a593Smuzhiyun 
1970*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_FINSTAT,	ctcmpc_chx_rx  },
1971*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_ATTN,		ctcmpc_chx_attn  },
1972*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1973*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_START,	ctcm_action_nop  },
1974*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1975*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1976*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_UC_ZERO,	ctcmpc_chx_rx  },
1977*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_UC_RCRESET,	ctcm_chx_setuperr  },
1978*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_UC_RSRESET,	ctcm_chx_setuperr  },
1979*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_ATTNBUSY,	ctcm_chx_iofatal  },
1980*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_TIMER,	ctcmpc_chx_resend  },
1981*4882a593Smuzhiyun 	{ CH_XID7_PENDING4,	CTC_EVENT_IO_EBUSY,	ctcm_chx_fail  },
1982*4882a593Smuzhiyun 
1983*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1984*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_START,	ctcm_action_nop  },
1985*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_FINSTAT,	ctcmpc_chx_rx  },
1986*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_UC_RCRESET,	ctcm_chx_rxdisc  },
1987*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_UC_RSRESET,	ctcm_chx_fail  },
1988*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1989*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
1990*4882a593Smuzhiyun 	{ CTC_STATE_RXIDLE,	CTC_EVENT_UC_ZERO,	ctcmpc_chx_rx  },
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
1993*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_START,	ctcm_action_nop  },
1994*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_FINSTAT,	ctcm_chx_txidle  },
1995*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_UC_RCRESET,	ctcm_chx_txiniterr  },
1996*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_UC_RSRESET,	ctcm_chx_txiniterr  },
1997*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_TIMER,	ctcm_chx_txiniterr  },
1998*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
1999*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
2000*4882a593Smuzhiyun 	{ CTC_STATE_TXINIT,	CTC_EVENT_RSWEEP_TIMER,	ctcmpc_chx_send_sweep },
2001*4882a593Smuzhiyun 
2002*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
2003*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_START,	ctcm_action_nop  },
2004*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_FINSTAT,	ctcmpc_chx_firstio  },
2005*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_UC_RCRESET,	ctcm_chx_fail  },
2006*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_UC_RSRESET,	ctcm_chx_fail  },
2007*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
2008*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
2009*4882a593Smuzhiyun 	{ CTC_STATE_TXIDLE,	CTC_EVENT_RSWEEP_TIMER,	ctcmpc_chx_send_sweep },
2010*4882a593Smuzhiyun 
2011*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_STOP,		ctcm_action_nop  },
2012*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_START,	ctcm_chx_restart  },
2013*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_FINSTAT,	ctcm_chx_stopped  },
2014*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_UC_RCRESET,	ctcm_action_nop  },
2015*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_UC_RSRESET,	ctcm_action_nop  },
2016*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
2017*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_IO_EBUSY,	ctcm_chx_fail  },
2018*4882a593Smuzhiyun 	{ CTC_STATE_TERM,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
2021*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_START,	ctcm_chx_restart  },
2022*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_FINSTAT,	ctcm_chx_setmode  },
2023*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_UC_RCRESET,	ctcm_action_nop  },
2024*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_UC_RSRESET,	ctcm_action_nop  },
2025*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
2026*4882a593Smuzhiyun 	{ CTC_STATE_DTERM,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
2027*4882a593Smuzhiyun 
2028*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_STOP,		ctcm_chx_haltio  },
2029*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_START,	ctcm_action_nop  },
2030*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_FINSTAT,	ctcmpc_chx_txdone  },
2031*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_UC_RCRESET,	ctcm_chx_fail  },
2032*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_UC_RSRESET,	ctcm_chx_fail  },
2033*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_TIMER,	ctcm_chx_txretry  },
2034*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
2035*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
2036*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_RSWEEP_TIMER,	ctcmpc_chx_send_sweep },
2037*4882a593Smuzhiyun 	{ CTC_STATE_TX,		CTC_EVENT_IO_EBUSY,	ctcm_chx_fail  },
2038*4882a593Smuzhiyun 
2039*4882a593Smuzhiyun 	{ CTC_STATE_RXERR,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
2040*4882a593Smuzhiyun 	{ CTC_STATE_TXERR,	CTC_EVENT_STOP,		ctcm_chx_haltio  },
2041*4882a593Smuzhiyun 	{ CTC_STATE_TXERR,	CTC_EVENT_IO_ENODEV,	ctcm_chx_iofatal  },
2042*4882a593Smuzhiyun 	{ CTC_STATE_TXERR,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
2043*4882a593Smuzhiyun 	{ CTC_STATE_RXERR,	CTC_EVENT_MC_FAIL,	ctcm_chx_fail  },
2044*4882a593Smuzhiyun };
2045*4882a593Smuzhiyun 
2046*4882a593Smuzhiyun int mpc_ch_fsm_len = ARRAY_SIZE(ctcmpc_ch_fsm);
2047*4882a593Smuzhiyun 
2048*4882a593Smuzhiyun /*
2049*4882a593Smuzhiyun  * Actions for interface - statemachine.
2050*4882a593Smuzhiyun  */
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun /**
2053*4882a593Smuzhiyun  * Startup channels by sending CTC_EVENT_START to each channel.
2054*4882a593Smuzhiyun  *
2055*4882a593Smuzhiyun  * fi		An instance of an interface statemachine.
2056*4882a593Smuzhiyun  * event	The event, just happened.
2057*4882a593Smuzhiyun  * arg		Generic pointer, casted from struct net_device * upon call.
2058*4882a593Smuzhiyun  */
dev_action_start(fsm_instance * fi,int event,void * arg)2059*4882a593Smuzhiyun static void dev_action_start(fsm_instance *fi, int event, void *arg)
2060*4882a593Smuzhiyun {
2061*4882a593Smuzhiyun 	struct net_device *dev = arg;
2062*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
2063*4882a593Smuzhiyun 	int direction;
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 	CTCMY_DBF_DEV_NAME(SETUP, dev, "");
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun 	fsm_deltimer(&priv->restart_timer);
2068*4882a593Smuzhiyun 	fsm_newstate(fi, DEV_STATE_STARTWAIT_RXTX);
2069*4882a593Smuzhiyun 	if (IS_MPC(priv))
2070*4882a593Smuzhiyun 		priv->mpcg->channels_terminating = 0;
2071*4882a593Smuzhiyun 	for (direction = CTCM_READ; direction <= CTCM_WRITE; direction++) {
2072*4882a593Smuzhiyun 		struct channel *ch = priv->channel[direction];
2073*4882a593Smuzhiyun 		fsm_event(ch->fsm, CTC_EVENT_START, ch);
2074*4882a593Smuzhiyun 	}
2075*4882a593Smuzhiyun }
2076*4882a593Smuzhiyun 
2077*4882a593Smuzhiyun /**
2078*4882a593Smuzhiyun  * Shutdown channels by sending CTC_EVENT_STOP to each channel.
2079*4882a593Smuzhiyun  *
2080*4882a593Smuzhiyun  * fi		An instance of an interface statemachine.
2081*4882a593Smuzhiyun  * event	The event, just happened.
2082*4882a593Smuzhiyun  * arg		Generic pointer, casted from struct net_device * upon call.
2083*4882a593Smuzhiyun  */
dev_action_stop(fsm_instance * fi,int event,void * arg)2084*4882a593Smuzhiyun static void dev_action_stop(fsm_instance *fi, int event, void *arg)
2085*4882a593Smuzhiyun {
2086*4882a593Smuzhiyun 	int direction;
2087*4882a593Smuzhiyun 	struct net_device *dev = arg;
2088*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
2089*4882a593Smuzhiyun 
2090*4882a593Smuzhiyun 	CTCMY_DBF_DEV_NAME(SETUP, dev, "");
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 	fsm_newstate(fi, DEV_STATE_STOPWAIT_RXTX);
2093*4882a593Smuzhiyun 	for (direction = CTCM_READ; direction <= CTCM_WRITE; direction++) {
2094*4882a593Smuzhiyun 		struct channel *ch = priv->channel[direction];
2095*4882a593Smuzhiyun 		fsm_event(ch->fsm, CTC_EVENT_STOP, ch);
2096*4882a593Smuzhiyun 		ch->th_seq_num = 0x00;
2097*4882a593Smuzhiyun 		CTCM_PR_DEBUG("%s: CH_th_seq= %08x\n",
2098*4882a593Smuzhiyun 				__func__, ch->th_seq_num);
2099*4882a593Smuzhiyun 	}
2100*4882a593Smuzhiyun 	if (IS_MPC(priv))
2101*4882a593Smuzhiyun 		fsm_newstate(priv->mpcg->fsm, MPCG_STATE_RESET);
2102*4882a593Smuzhiyun }
2103*4882a593Smuzhiyun 
dev_action_restart(fsm_instance * fi,int event,void * arg)2104*4882a593Smuzhiyun static void dev_action_restart(fsm_instance *fi, int event, void *arg)
2105*4882a593Smuzhiyun {
2106*4882a593Smuzhiyun 	int restart_timer;
2107*4882a593Smuzhiyun 	struct net_device *dev = arg;
2108*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun 	CTCMY_DBF_DEV_NAME(TRACE, dev, "");
2111*4882a593Smuzhiyun 
2112*4882a593Smuzhiyun 	if (IS_MPC(priv)) {
2113*4882a593Smuzhiyun 		restart_timer = CTCM_TIME_1_SEC;
2114*4882a593Smuzhiyun 	} else {
2115*4882a593Smuzhiyun 		restart_timer = CTCM_TIME_5_SEC;
2116*4882a593Smuzhiyun 	}
2117*4882a593Smuzhiyun 	dev_info(&dev->dev, "Restarting device\n");
2118*4882a593Smuzhiyun 
2119*4882a593Smuzhiyun 	dev_action_stop(fi, event, arg);
2120*4882a593Smuzhiyun 	fsm_event(priv->fsm, DEV_EVENT_STOP, dev);
2121*4882a593Smuzhiyun 	if (IS_MPC(priv))
2122*4882a593Smuzhiyun 		fsm_newstate(priv->mpcg->fsm, MPCG_STATE_RESET);
2123*4882a593Smuzhiyun 
2124*4882a593Smuzhiyun 	/* going back into start sequence too quickly can	  */
2125*4882a593Smuzhiyun 	/* result in the other side becoming unreachable   due	  */
2126*4882a593Smuzhiyun 	/* to sense reported when IO is aborted			  */
2127*4882a593Smuzhiyun 	fsm_addtimer(&priv->restart_timer, restart_timer,
2128*4882a593Smuzhiyun 			DEV_EVENT_START, dev);
2129*4882a593Smuzhiyun }
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun /**
2132*4882a593Smuzhiyun  * Called from channel statemachine
2133*4882a593Smuzhiyun  * when a channel is up and running.
2134*4882a593Smuzhiyun  *
2135*4882a593Smuzhiyun  * fi		An instance of an interface statemachine.
2136*4882a593Smuzhiyun  * event	The event, just happened.
2137*4882a593Smuzhiyun  * arg		Generic pointer, casted from struct net_device * upon call.
2138*4882a593Smuzhiyun  */
dev_action_chup(fsm_instance * fi,int event,void * arg)2139*4882a593Smuzhiyun static void dev_action_chup(fsm_instance *fi, int event, void *arg)
2140*4882a593Smuzhiyun {
2141*4882a593Smuzhiyun 	struct net_device *dev = arg;
2142*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
2143*4882a593Smuzhiyun 	int dev_stat = fsm_getstate(fi);
2144*4882a593Smuzhiyun 
2145*4882a593Smuzhiyun 	CTCM_DBF_TEXT_(SETUP, CTC_DBF_NOTICE,
2146*4882a593Smuzhiyun 			"%s(%s): priv = %p [%d,%d]\n ",	CTCM_FUNTAIL,
2147*4882a593Smuzhiyun 				dev->name, dev->ml_priv, dev_stat, event);
2148*4882a593Smuzhiyun 
2149*4882a593Smuzhiyun 	switch (fsm_getstate(fi)) {
2150*4882a593Smuzhiyun 	case DEV_STATE_STARTWAIT_RXTX:
2151*4882a593Smuzhiyun 		if (event == DEV_EVENT_RXUP)
2152*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
2153*4882a593Smuzhiyun 		else
2154*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STARTWAIT_RX);
2155*4882a593Smuzhiyun 		break;
2156*4882a593Smuzhiyun 	case DEV_STATE_STARTWAIT_RX:
2157*4882a593Smuzhiyun 		if (event == DEV_EVENT_RXUP) {
2158*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_RUNNING);
2159*4882a593Smuzhiyun 			dev_info(&dev->dev,
2160*4882a593Smuzhiyun 				"Connected with remote side\n");
2161*4882a593Smuzhiyun 			ctcm_clear_busy(dev);
2162*4882a593Smuzhiyun 		}
2163*4882a593Smuzhiyun 		break;
2164*4882a593Smuzhiyun 	case DEV_STATE_STARTWAIT_TX:
2165*4882a593Smuzhiyun 		if (event == DEV_EVENT_TXUP) {
2166*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_RUNNING);
2167*4882a593Smuzhiyun 			dev_info(&dev->dev,
2168*4882a593Smuzhiyun 				"Connected with remote side\n");
2169*4882a593Smuzhiyun 			ctcm_clear_busy(dev);
2170*4882a593Smuzhiyun 		}
2171*4882a593Smuzhiyun 		break;
2172*4882a593Smuzhiyun 	case DEV_STATE_STOPWAIT_TX:
2173*4882a593Smuzhiyun 		if (event == DEV_EVENT_RXUP)
2174*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STOPWAIT_RXTX);
2175*4882a593Smuzhiyun 		break;
2176*4882a593Smuzhiyun 	case DEV_STATE_STOPWAIT_RX:
2177*4882a593Smuzhiyun 		if (event == DEV_EVENT_TXUP)
2178*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STOPWAIT_RXTX);
2179*4882a593Smuzhiyun 		break;
2180*4882a593Smuzhiyun 	}
2181*4882a593Smuzhiyun 
2182*4882a593Smuzhiyun 	if (IS_MPC(priv)) {
2183*4882a593Smuzhiyun 		if (event == DEV_EVENT_RXUP)
2184*4882a593Smuzhiyun 			mpc_channel_action(priv->channel[CTCM_READ],
2185*4882a593Smuzhiyun 				CTCM_READ, MPC_CHANNEL_ADD);
2186*4882a593Smuzhiyun 		else
2187*4882a593Smuzhiyun 			mpc_channel_action(priv->channel[CTCM_WRITE],
2188*4882a593Smuzhiyun 				CTCM_WRITE, MPC_CHANNEL_ADD);
2189*4882a593Smuzhiyun 	}
2190*4882a593Smuzhiyun }
2191*4882a593Smuzhiyun 
2192*4882a593Smuzhiyun /**
2193*4882a593Smuzhiyun  * Called from device statemachine
2194*4882a593Smuzhiyun  * when a channel has been shutdown.
2195*4882a593Smuzhiyun  *
2196*4882a593Smuzhiyun  * fi		An instance of an interface statemachine.
2197*4882a593Smuzhiyun  * event	The event, just happened.
2198*4882a593Smuzhiyun  * arg		Generic pointer, casted from struct net_device * upon call.
2199*4882a593Smuzhiyun  */
dev_action_chdown(fsm_instance * fi,int event,void * arg)2200*4882a593Smuzhiyun static void dev_action_chdown(fsm_instance *fi, int event, void *arg)
2201*4882a593Smuzhiyun {
2202*4882a593Smuzhiyun 
2203*4882a593Smuzhiyun 	struct net_device *dev = arg;
2204*4882a593Smuzhiyun 	struct ctcm_priv *priv = dev->ml_priv;
2205*4882a593Smuzhiyun 
2206*4882a593Smuzhiyun 	CTCMY_DBF_DEV_NAME(SETUP, dev, "");
2207*4882a593Smuzhiyun 
2208*4882a593Smuzhiyun 	switch (fsm_getstate(fi)) {
2209*4882a593Smuzhiyun 	case DEV_STATE_RUNNING:
2210*4882a593Smuzhiyun 		if (event == DEV_EVENT_TXDOWN)
2211*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
2212*4882a593Smuzhiyun 		else
2213*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STARTWAIT_RX);
2214*4882a593Smuzhiyun 		break;
2215*4882a593Smuzhiyun 	case DEV_STATE_STARTWAIT_RX:
2216*4882a593Smuzhiyun 		if (event == DEV_EVENT_TXDOWN)
2217*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STARTWAIT_RXTX);
2218*4882a593Smuzhiyun 		break;
2219*4882a593Smuzhiyun 	case DEV_STATE_STARTWAIT_TX:
2220*4882a593Smuzhiyun 		if (event == DEV_EVENT_RXDOWN)
2221*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STARTWAIT_RXTX);
2222*4882a593Smuzhiyun 		break;
2223*4882a593Smuzhiyun 	case DEV_STATE_STOPWAIT_RXTX:
2224*4882a593Smuzhiyun 		if (event == DEV_EVENT_TXDOWN)
2225*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STOPWAIT_RX);
2226*4882a593Smuzhiyun 		else
2227*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STOPWAIT_TX);
2228*4882a593Smuzhiyun 		break;
2229*4882a593Smuzhiyun 	case DEV_STATE_STOPWAIT_RX:
2230*4882a593Smuzhiyun 		if (event == DEV_EVENT_RXDOWN)
2231*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STOPPED);
2232*4882a593Smuzhiyun 		break;
2233*4882a593Smuzhiyun 	case DEV_STATE_STOPWAIT_TX:
2234*4882a593Smuzhiyun 		if (event == DEV_EVENT_TXDOWN)
2235*4882a593Smuzhiyun 			fsm_newstate(fi, DEV_STATE_STOPPED);
2236*4882a593Smuzhiyun 		break;
2237*4882a593Smuzhiyun 	}
2238*4882a593Smuzhiyun 	if (IS_MPC(priv)) {
2239*4882a593Smuzhiyun 		if (event == DEV_EVENT_RXDOWN)
2240*4882a593Smuzhiyun 			mpc_channel_action(priv->channel[CTCM_READ],
2241*4882a593Smuzhiyun 				CTCM_READ, MPC_CHANNEL_REMOVE);
2242*4882a593Smuzhiyun 		else
2243*4882a593Smuzhiyun 			mpc_channel_action(priv->channel[CTCM_WRITE],
2244*4882a593Smuzhiyun 				CTCM_WRITE, MPC_CHANNEL_REMOVE);
2245*4882a593Smuzhiyun 	}
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun 
2248*4882a593Smuzhiyun const fsm_node dev_fsm[] = {
2249*4882a593Smuzhiyun 	{ DEV_STATE_STOPPED,        DEV_EVENT_START,   dev_action_start   },
2250*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RXTX,  DEV_EVENT_START,   dev_action_start   },
2251*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RXTX,  DEV_EVENT_RXDOWN,  dev_action_chdown  },
2252*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RXTX,  DEV_EVENT_TXDOWN,  dev_action_chdown  },
2253*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RXTX,  DEV_EVENT_RESTART, dev_action_restart },
2254*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RX,    DEV_EVENT_START,   dev_action_start   },
2255*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RX,    DEV_EVENT_RXUP,    dev_action_chup    },
2256*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RX,    DEV_EVENT_TXUP,    dev_action_chup    },
2257*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RX,    DEV_EVENT_RXDOWN,  dev_action_chdown  },
2258*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_RX,    DEV_EVENT_RESTART, dev_action_restart },
2259*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_TX,    DEV_EVENT_START,   dev_action_start   },
2260*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_TX,    DEV_EVENT_RXUP,    dev_action_chup    },
2261*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_TX,    DEV_EVENT_TXUP,    dev_action_chup    },
2262*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_TX,    DEV_EVENT_TXDOWN,  dev_action_chdown  },
2263*4882a593Smuzhiyun 	{ DEV_STATE_STOPWAIT_TX,    DEV_EVENT_RESTART, dev_action_restart },
2264*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_STOP,    dev_action_stop    },
2265*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_RXUP,    dev_action_chup    },
2266*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_TXUP,    dev_action_chup    },
2267*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_RXDOWN,  dev_action_chdown  },
2268*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_TXDOWN,  dev_action_chdown  },
2269*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_RESTART, dev_action_restart },
2270*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_TX,   DEV_EVENT_STOP,    dev_action_stop    },
2271*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_TX,   DEV_EVENT_RXUP,    dev_action_chup    },
2272*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_TX,   DEV_EVENT_TXUP,    dev_action_chup    },
2273*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_TX,   DEV_EVENT_RXDOWN,  dev_action_chdown  },
2274*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_TX,   DEV_EVENT_RESTART, dev_action_restart },
2275*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RX,   DEV_EVENT_STOP,    dev_action_stop    },
2276*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RX,   DEV_EVENT_RXUP,    dev_action_chup    },
2277*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RX,   DEV_EVENT_TXUP,    dev_action_chup    },
2278*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RX,   DEV_EVENT_TXDOWN,  dev_action_chdown  },
2279*4882a593Smuzhiyun 	{ DEV_STATE_STARTWAIT_RX,   DEV_EVENT_RESTART, dev_action_restart },
2280*4882a593Smuzhiyun 	{ DEV_STATE_RUNNING,        DEV_EVENT_STOP,    dev_action_stop    },
2281*4882a593Smuzhiyun 	{ DEV_STATE_RUNNING,        DEV_EVENT_RXDOWN,  dev_action_chdown  },
2282*4882a593Smuzhiyun 	{ DEV_STATE_RUNNING,        DEV_EVENT_TXDOWN,  dev_action_chdown  },
2283*4882a593Smuzhiyun 	{ DEV_STATE_RUNNING,        DEV_EVENT_TXUP,    ctcm_action_nop    },
2284*4882a593Smuzhiyun 	{ DEV_STATE_RUNNING,        DEV_EVENT_RXUP,    ctcm_action_nop    },
2285*4882a593Smuzhiyun 	{ DEV_STATE_RUNNING,        DEV_EVENT_RESTART, dev_action_restart },
2286*4882a593Smuzhiyun };
2287*4882a593Smuzhiyun 
2288*4882a593Smuzhiyun int dev_fsm_len = ARRAY_SIZE(dev_fsm);
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun /* --- This is the END my friend --- */
2291*4882a593Smuzhiyun 
2292