1/*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 *---------------------------------------------------------------------------
26 *
27 *	i4b_l1fsm.c - isdn4bsd layer 1 I.430 state machine
28 *	--------------------------------------------------
29 *
30 *	$Id: isic_l1fsm.c,v 1.14 2011/07/17 20:54:51 joerg Exp $
31 *
32 *      last edit-date: [Fri Jan  5 11:36:11 2001]
33 *
34 *---------------------------------------------------------------------------*/
35
36#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: isic_l1fsm.c,v 1.13 2007/10/19 11:59:54 ad Exp $");
38
39#include <sys/param.h>
40#if defined(__FreeBSD__) && __FreeBSD__ >= 3
41#include <sys/ioccom.h>
42#else
43#include <sys/ioctl.h>
44#endif
45#include <sys/kernel.h>
46#include <sys/systm.h>
47#include <sys/mbuf.h>
48
49#ifdef __FreeBSD__
50#include <machine/clock.h>
51#include <i386/isa/isa_device.h>
52#else
53#ifndef __bsdi__
54#include <sys/bus.h>
55#endif
56#include <sys/device.h>
57#endif
58
59#include <sys/socket.h>
60#include <net/if.h>
61
62#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
63#include <sys/callout.h>
64#endif
65
66#ifdef __FreeBSD__
67#include <machine/i4b_debug.h>
68#include <machine/i4b_ioctl.h>
69#else
70#include <netisdn/i4b_debug.h>
71#include <netisdn/i4b_ioctl.h>
72#endif
73
74#include <netisdn/i4b_global.h>
75#include <netisdn/i4b_trace.h>
76#include <netisdn/i4b_l2.h>
77#include <netisdn/i4b_l1l2.h>
78#include <netisdn/i4b_mbuf.h>
79
80#include <dev/ic/isic_l1.h>
81#include <dev/ic/isac.h>
82#include <dev/ic/hscx.h>
83
84#include "nisac.h"
85#include "nisacsx.h"
86
87#if DO_I4B_DEBUG
88static const char *state_text[N_STATES] = {
89	"F3 Deactivated",
90	"F4 Awaiting Signal",
91	"F5 Identifying Input",
92	"F6 Synchronized",
93	"F7 Activated",
94	"F8 Lost Framing",
95	"Illegal State"
96};
97
98static const char *event_text[N_EVENTS] = {
99	"EV_PHAR PH_ACT_REQ",
100	"EV_T3 Timer 3 expired",
101	"EV_INFO0 INFO0 received",
102	"EV_RSY Level Detected",
103	"EV_INFO2 INFO2 received",
104	"EV_INFO48 INFO4 received",
105	"EV_INFO410 INFO4 received",
106	"EV_DR Deactivate Req",
107	"EV_PU Power UP",
108	"EV_DIS Disconnected",
109	"EV_EI Error Ind",
110	"Illegal Event"
111};
112#endif
113
114/* Function prototypes */
115
116static void timer3_expired (struct isic_softc *sc);
117static void T3_start (struct isic_softc *sc);
118static void T3_stop (struct isic_softc *sc);
119static void F_T3ex (struct isic_softc *sc);
120static void timer4_expired (struct isic_softc *sc);
121static void T4_start (struct isic_softc *sc);
122static void T4_stop (struct isic_softc *sc);
123static void F_AI8 (struct isic_softc *sc);
124static void F_AI10 (struct isic_softc *sc);
125static void F_I01 (struct isic_softc *sc);
126static void F_I02 (struct isic_softc *sc);
127static void F_I03 (struct isic_softc *sc);
128static void F_I2 (struct isic_softc *sc);
129static void F_ill (struct isic_softc *sc);
130static void F_NULL (struct isic_softc *sc);
131
132/*---------------------------------------------------------------------------*
133 *	I.430 Timer T3 expire function
134 *---------------------------------------------------------------------------*/
135static void
136timer3_expired(struct isic_softc *sc)
137{
138	if(sc->sc_I430T3)
139	{
140		NDBGL1(L1_T_ERR, "state = %s", isic_printstate(sc));
141		sc->sc_I430T3 = 0;
142
143		/* XXX try some recovery here XXX */
144		switch(sc->sc_cardtyp) {
145#if NNISACSX > 0
146			case CARD_TYPEP_AVMA1PCIV2:
147				isic_isacsx_recover(sc);
148				break;
149#endif /* NNISACSX > 0 */
150			default:
151#if NNISAC > 0
152				isic_recover(sc);
153#endif /* NNISAC > 0 */
154				break;
155		}
156
157		sc->sc_init_tries++;	/* increment retry count */
158
159/*XXX*/		if(sc->sc_init_tries > 4)
160		{
161			int s = splnet();
162
163			sc->sc_init_tries = 0;
164
165			if(sc->sc_obuf2 != NULL)
166			{
167				i4b_Dfreembuf(sc->sc_obuf2);
168				sc->sc_obuf2 = NULL;
169			}
170			if(sc->sc_obuf != NULL)
171			{
172				i4b_Dfreembuf(sc->sc_obuf);
173				sc->sc_obuf = NULL;
174				sc->sc_freeflag = 0;
175				sc->sc_op = NULL;
176				sc->sc_ol = 0;
177			}
178
179			splx(s);
180
181			isdn_layer2_status_ind(&sc->sc_l2, sc->sc_l3token, STI_NOL1ACC, 0);
182		}
183
184		isic_next_state(sc, EV_T3);
185	}
186	else
187	{
188		NDBGL1(L1_T_ERR, "expired without starting it ....");
189	}
190}
191
192/*---------------------------------------------------------------------------*
193 *	I.430 Timer T3 start
194 *---------------------------------------------------------------------------*/
195static void
196T3_start(struct isic_softc *sc)
197{
198	NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc));
199	sc->sc_I430T3 = 1;
200
201	START_TIMER(sc->sc_T3_callout, timer3_expired, sc, 2*hz);
202}
203
204/*---------------------------------------------------------------------------*
205 *	I.430 Timer T3 stop
206 *---------------------------------------------------------------------------*/
207static void
208T3_stop(struct isic_softc *sc)
209{
210	NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc));
211
212	sc->sc_init_tries = 0;	/* init connect retry count */
213
214	if(sc->sc_I430T3)
215	{
216		sc->sc_I430T3 = 0;
217		STOP_TIMER(sc->sc_T3_callout, timer3_expired, sc);
218	}
219}
220
221/*---------------------------------------------------------------------------*
222 *	I.430 Timer T3 expiry
223 *---------------------------------------------------------------------------*/
224static void
225F_T3ex(struct isic_softc *sc)
226{
227	NDBGL1(L1_F_MSG, "FSM function F_T3ex executing");
228	if(((struct isdn_l3_driver*)sc->sc_l3token)->protocol != PROTOCOL_D64S)
229		isdn_layer2_activate_ind(&sc->sc_l2, sc->sc_l3token, 0);
230}
231
232/*---------------------------------------------------------------------------*
233 *	Timer T4 expire function
234 *---------------------------------------------------------------------------*/
235static void
236timer4_expired(struct isic_softc *sc)
237{
238	if(sc->sc_I430T4)
239	{
240		NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc));
241		sc->sc_I430T4 = 0;
242		isdn_layer2_status_ind(&sc->sc_l2, sc->sc_l3token, STI_PDEACT, 0);
243	}
244	else
245	{
246		NDBGL1(L1_T_ERR, "expired without starting it ....");
247	}
248}
249
250/*---------------------------------------------------------------------------*
251 *	Timer T4 start
252 *---------------------------------------------------------------------------*/
253static void
254T4_start(struct isic_softc *sc)
255{
256	NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc));
257	sc->sc_I430T4 = 1;
258
259	START_TIMER(sc->sc_T4_callout, timer4_expired, sc, hz);
260}
261
262/*---------------------------------------------------------------------------*
263 *	Timer T4 stop
264 *---------------------------------------------------------------------------*/
265static void
266T4_stop(struct isic_softc *sc)
267{
268	NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc));
269
270	if(sc->sc_I430T4)
271	{
272		sc->sc_I430T4 = 0;
273		STOP_TIMER(sc->sc_T4_callout, timer4_expired, sc);
274	}
275}
276
277/*---------------------------------------------------------------------------*
278 *	FSM function: received AI8
279 *---------------------------------------------------------------------------*/
280static void
281F_AI8(struct isic_softc *sc)
282{
283	T4_stop(sc);
284
285	NDBGL1(L1_F_MSG, "FSM function F_AI8 executing");
286
287	if(((struct isdn_l3_driver*)sc->sc_l3token)->protocol != PROTOCOL_D64S)
288		isdn_layer2_activate_ind(&sc->sc_l2, sc->sc_l3token, 1);
289
290	T3_stop(sc);
291
292	if(sc->sc_trace & TRACE_I)
293	{
294		i4b_trace_hdr hdr;
295		char info = INFO4_8;
296
297		hdr.type = TRC_CH_I;
298		hdr.dir = FROM_NT;
299		hdr.count = 0;
300		isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, 1, &info);
301	}
302}
303
304/*---------------------------------------------------------------------------*
305 *	FSM function: received AI10
306 *---------------------------------------------------------------------------*/
307static void
308F_AI10(struct isic_softc *sc)
309{
310	T4_stop(sc);
311
312	NDBGL1(L1_F_MSG, "FSM function F_AI10 executing");
313
314	if(((struct isdn_l3_driver*)sc->sc_l3token)->protocol != PROTOCOL_D64S)
315		isdn_layer2_activate_ind(&sc->sc_l2, sc->sc_l3token, 1);
316
317	T3_stop(sc);
318
319	if(sc->sc_trace & TRACE_I)
320	{
321		i4b_trace_hdr hdr;
322		char info = INFO4_10;
323
324		hdr.type = TRC_CH_I;
325		hdr.dir = FROM_NT;
326		hdr.count = 0;
327		isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, 1, &info);
328	}
329}
330
331/*---------------------------------------------------------------------------*
332 *	FSM function: received INFO 0 in states F3 .. F5
333 *---------------------------------------------------------------------------*/
334static void
335F_I01(struct isic_softc *sc)
336{
337	NDBGL1(L1_F_MSG, "FSM function F_I01 executing");
338
339	if(sc->sc_trace & TRACE_I)
340	{
341		i4b_trace_hdr hdr;
342		char info = INFO0;
343
344		hdr.type = TRC_CH_I;
345		hdr.dir = FROM_NT;
346		hdr.count = 0;
347		isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, 1, &info);
348	}
349}
350
351/*---------------------------------------------------------------------------*
352 *	FSM function: received INFO 0 in state F6
353 *---------------------------------------------------------------------------*/
354static void
355F_I02(struct isic_softc *sc)
356{
357	NDBGL1(L1_F_MSG, "FSM function F_I02 executing");
358
359	if(((struct isdn_l3_driver*)sc->sc_l3token)->protocol != PROTOCOL_D64S)
360		isdn_layer2_activate_ind(&sc->sc_l2, sc->sc_l3token, 0);
361
362	if(sc->sc_trace & TRACE_I)
363	{
364		i4b_trace_hdr hdr;
365		char info = INFO0;
366
367		hdr.type = TRC_CH_I;
368		hdr.dir = FROM_NT;
369		hdr.count = 0;
370		isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, 1, &info);
371	}
372}
373
374/*---------------------------------------------------------------------------*
375 *	FSM function: received INFO 0 in state F7 or F8
376 *---------------------------------------------------------------------------*/
377static void
378F_I03(struct isic_softc *sc)
379{
380	NDBGL1(L1_F_MSG, "FSM function F_I03 executing");
381
382	if(((struct isdn_l3_driver*)sc->sc_l3token)->protocol != PROTOCOL_D64S)
383		isdn_layer2_activate_ind(&sc->sc_l2, sc->sc_l3token, 0);
384
385	T4_start(sc);
386
387	if(sc->sc_trace & TRACE_I)
388	{
389		i4b_trace_hdr hdr;
390		char info = INFO0;
391
392		hdr.type = TRC_CH_I;
393		hdr.dir = FROM_NT;
394		hdr.count = 0;
395		isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, 1, &info);
396	}
397}
398
399/*---------------------------------------------------------------------------*
400 *	FSM function: activate request
401 *---------------------------------------------------------------------------*/
402static void
403F_AR(struct isic_softc *sc)
404{
405	NDBGL1(L1_F_MSG, "FSM function F_AR executing");
406
407	if(sc->sc_trace & TRACE_I)
408	{
409		i4b_trace_hdr hdr;
410		char info = INFO1_8;
411
412		hdr.type = TRC_CH_I;
413		hdr.dir = FROM_TE;
414		hdr.count = 0;
415		isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, 1, &info);
416	}
417
418	switch(sc->sc_cardtyp) {
419#if NNISACSX > 0
420		case CARD_TYPEP_AVMA1PCIV2:
421			isic_isacsx_l1_cmd(sc, CMD_AR8);
422			break;
423#endif /* NNISACSX > 0 */
424		default:
425#if NNISAC > 0
426			isic_isac_l1_cmd(sc, CMD_AR8);
427#endif /* NNISAC > 0 */
428			break;
429	}
430
431	T3_start(sc);
432}
433
434/*---------------------------------------------------------------------------*
435 *	FSM function: received INFO2
436 *---------------------------------------------------------------------------*/
437static void
438F_I2(struct isic_softc *sc)
439{
440	NDBGL1(L1_F_MSG, "FSM function F_I2 executing");
441
442	if(sc->sc_trace & TRACE_I)
443	{
444		i4b_trace_hdr hdr;
445		char info = INFO2;
446
447		hdr.type = TRC_CH_I;
448		hdr.dir = FROM_NT;
449		hdr.count = 0;
450		isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, 1, &info);
451	}
452}
453
454/*---------------------------------------------------------------------------*
455 *	illegal state default action
456 *---------------------------------------------------------------------------*/
457static void
458F_ill(struct isic_softc *sc)
459{
460	NDBGL1(L1_F_ERR, "FSM function F_ill executing");
461}
462
463/*---------------------------------------------------------------------------*
464 *	No action
465 *---------------------------------------------------------------------------*/
466static void
467F_NULL(struct isic_softc *sc)
468{
469	NDBGL1(L1_F_MSG, "FSM function F_NULL executing");
470}
471
472
473/*---------------------------------------------------------------------------*
474 *	layer 1 state transition table
475 *---------------------------------------------------------------------------*/
476struct isic_state_tab {
477	void (*func) (struct isic_softc *sc);	/* function to execute */
478	int newstate;				/* next state */
479} isic_state_tab[N_EVENTS][N_STATES] = {
480
481/* STATE:	F3			F4			F5			F6			F7			F8			ILLEGAL STATE     */
482/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
483/* EV_PHAR x*/	{{F_AR,   ST_F4},	{F_NULL, ST_F4},	{F_NULL, ST_F5},	{F_NULL, ST_F6},	{F_ill,  ST_ILL},	{F_NULL, ST_F8},	{F_ill, ST_ILL}},
484/* EV_T3   x*/	{{F_NULL, ST_F3},	{F_T3ex, ST_F3},	{F_T3ex, ST_F3},	{F_T3ex, ST_F3},	{F_NULL, ST_F7},	{F_NULL, ST_F8},	{F_ill, ST_ILL}},
485/* EV_INFO0 */	{{F_I01,  ST_F3},	{F_I01,  ST_F4},	{F_I01,  ST_F5},	{F_I02,  ST_F3},	{F_I03,  ST_F3},	{F_I03,  ST_F3},	{F_ill, ST_ILL}},
486/* EV_RSY  x*/	{{F_NULL, ST_F3},	{F_NULL, ST_F5},	{F_NULL, ST_F5}, 	{F_NULL, ST_F8},	{F_NULL, ST_F8},	{F_NULL, ST_F8},	{F_ill, ST_ILL}},
487/* EV_INFO2 */	{{F_I2,   ST_F6},	{F_I2,   ST_F6},	{F_I2,   ST_F6},	{F_I2,   ST_F6},	{F_I2,   ST_F6},	{F_I2,   ST_F6},	{F_ill, ST_ILL}},
488/* EV_INFO48*/	{{F_AI8,  ST_F7},	{F_AI8,  ST_F7},	{F_AI8,  ST_F7},	{F_AI8,  ST_F7},	{F_NULL, ST_F7},	{F_AI8,  ST_F7},	{F_ill, ST_ILL}},
489/* EV_INFO41*/	{{F_AI10, ST_F7},	{F_AI10, ST_F7},	{F_AI10, ST_F7},	{F_AI10, ST_F7},	{F_NULL, ST_F7},	{F_AI10, ST_F7},	{F_ill, ST_ILL}},
490/* EV_DR    */	{{F_NULL, ST_F3},	{F_NULL, ST_F4},	{F_NULL, ST_F5},	{F_NULL, ST_F6},	{F_NULL, ST_F7},	{F_NULL, ST_F8},	{F_ill, ST_ILL}},
491/* EV_PU    */	{{F_NULL, ST_F3},	{F_NULL, ST_F4},	{F_NULL, ST_F5},	{F_NULL, ST_F6},	{F_NULL, ST_F7},	{F_NULL, ST_F8},	{F_ill, ST_ILL}},
492/* EV_DIS   */	{{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill, ST_ILL}},
493/* EV_EI    */	{{F_NULL, ST_F3},	{F_NULL, ST_F3},	{F_NULL, ST_F3},	{F_NULL, ST_F3},	{F_NULL, ST_F3},	{F_NULL, ST_F3},	{F_ill, ST_ILL}},
494/* EV_ILL   */	{{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill,  ST_ILL},	{F_ill, ST_ILL}}
495};
496
497/*---------------------------------------------------------------------------*
498 *	event handler
499 *---------------------------------------------------------------------------*/
500void
501isic_next_state(struct isic_softc *sc, int event)
502{
503	int currstate, newstate;
504
505	if(event >= N_EVENTS)
506		panic("i4b_l1fsm.c: event >= N_EVENTS");
507
508	currstate = sc->sc_I430state;
509
510	if(currstate >= N_STATES)
511		panic("i4b_l1fsm.c: currstate >= N_STATES");
512
513	newstate = isic_state_tab[event][currstate].newstate;
514
515	if(newstate >= N_STATES)
516		panic("i4b_l1fsm.c: newstate >= N_STATES");
517
518	NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event],
519                                           state_text[currstate],
520                                           state_text[newstate]);
521
522        (*isic_state_tab[event][currstate].func)(sc);
523
524	if(newstate == ST_ILL)
525	{
526		newstate = ST_F3;
527		NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!",
528					state_text[currstate],
529					state_text[newstate],
530					event_text[event]);
531	}
532
533	sc->sc_I430state = newstate;
534}
535
536#if DO_I4B_DEBUG
537/*---------------------------------------------------------------------------*
538 *	return pointer to current state description
539 *---------------------------------------------------------------------------*/
540const char *
541isic_printstate(struct isic_softc *sc)
542{
543	return(state_text[sc->sc_I430state]);
544}
545#endif
546