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.14 2011/07/17 20:54:51 joerg 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
88 static 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 
98 static 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 
116 static void timer3_expired (struct isic_softc *sc);
117 static void T3_start (struct isic_softc *sc);
118 static void T3_stop (struct isic_softc *sc);
119 static void F_T3ex (struct isic_softc *sc);
120 static void timer4_expired (struct isic_softc *sc);
121 static void T4_start (struct isic_softc *sc);
122 static void T4_stop (struct isic_softc *sc);
123 static void F_AI8 (struct isic_softc *sc);
124 static void F_AI10 (struct isic_softc *sc);
125 static void F_I01 (struct isic_softc *sc);
126 static void F_I02 (struct isic_softc *sc);
127 static void F_I03 (struct isic_softc *sc);
128 static void F_I2 (struct isic_softc *sc);
129 static void F_ill (struct isic_softc *sc);
130 static void F_NULL (struct isic_softc *sc);
131 
132 /*---------------------------------------------------------------------------*
133  *	I.430 Timer T3 expire function
134  *---------------------------------------------------------------------------*/
135 static void
timer3_expired(struct isic_softc * sc)136 timer3_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  *---------------------------------------------------------------------------*/
195 static void
T3_start(struct isic_softc * sc)196 T3_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  *---------------------------------------------------------------------------*/
207 static void
T3_stop(struct isic_softc * sc)208 T3_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  *---------------------------------------------------------------------------*/
224 static void
F_T3ex(struct isic_softc * sc)225 F_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  *---------------------------------------------------------------------------*/
235 static void
timer4_expired(struct isic_softc * sc)236 timer4_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  *---------------------------------------------------------------------------*/
253 static void
T4_start(struct isic_softc * sc)254 T4_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  *---------------------------------------------------------------------------*/
265 static void
T4_stop(struct isic_softc * sc)266 T4_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  *---------------------------------------------------------------------------*/
280 static void
F_AI8(struct isic_softc * sc)281 F_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  *---------------------------------------------------------------------------*/
307 static void
F_AI10(struct isic_softc * sc)308 F_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  *---------------------------------------------------------------------------*/
334 static void
F_I01(struct isic_softc * sc)335 F_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  *---------------------------------------------------------------------------*/
354 static void
F_I02(struct isic_softc * sc)355 F_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  *---------------------------------------------------------------------------*/
377 static void
F_I03(struct isic_softc * sc)378 F_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  *---------------------------------------------------------------------------*/
402 static void
F_AR(struct isic_softc * sc)403 F_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  *---------------------------------------------------------------------------*/
437 static void
F_I2(struct isic_softc * sc)438 F_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  *---------------------------------------------------------------------------*/
457 static void
F_ill(struct isic_softc * sc)458 F_ill(struct isic_softc *sc)
459 {
460 	NDBGL1(L1_F_ERR, "FSM function F_ill executing");
461 }
462 
463 /*---------------------------------------------------------------------------*
464  *	No action
465  *---------------------------------------------------------------------------*/
466 static void
F_NULL(struct isic_softc * sc)467 F_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  *---------------------------------------------------------------------------*/
476 struct 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  *---------------------------------------------------------------------------*/
500 void
isic_next_state(struct isic_softc * sc,int event)501 isic_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  *---------------------------------------------------------------------------*/
540 const char *
isic_printstate(struct isic_softc * sc)541 isic_printstate(struct isic_softc *sc)
542 {
543 	return(state_text[sc->sc_I430state]);
544 }
545 #endif
546