xref: /csrg-svn/sys/vax/if/if_acp.c (revision 45679)
1*45679Sbostic 
2*45679Sbostic /*	if_acp.c	 	V2.3		01/19/88	*/
3*45679Sbostic 
4*45679Sbostic /*************************************************************************/
5*45679Sbostic /*                                                                       */
6*45679Sbostic /*                                                                       */
7*45679Sbostic /*       ________________________________________________________        */
8*45679Sbostic /*      /                                                        \       */
9*45679Sbostic /*     |          AAA          CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |      */
10*45679Sbostic /*     |         AAAAA        CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |      */
11*45679Sbostic /*     |        AAAAAAA       CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |      */
12*45679Sbostic /*     |       AAAA AAAA      CCCC              CCCC              |      */
13*45679Sbostic /*     |      AAAA   AAAA     CCCC              CCCC              |      */
14*45679Sbostic /*     |     AAAA     AAAA    CCCC              CCCC              |      */
15*45679Sbostic /*     |    AAAA       AAAA   CCCC              CCCC              |      */
16*45679Sbostic /*     |   AAAA  AAAAAAAAAAA  CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |      */
17*45679Sbostic /*     |  AAAA    AAAAAAAAAAA CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |      */
18*45679Sbostic /*     | AAAA      AAAAAAAAA   CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |      */
19*45679Sbostic /*      \________________________________________________________/       */
20*45679Sbostic /*                                                                       */
21*45679Sbostic /*  	Copyright (c) 1985 by Advanced Computer Communications           */
22*45679Sbostic /*  	720 Santa Barbara Street, Santa Barbara, California  93101       */
23*45679Sbostic /*  	(805) 963-9431                                                   */
24*45679Sbostic /*                                                                       */
25*45679Sbostic /*                                                                       */
26*45679Sbostic /*  File:		if_acp.c                                         */
27*45679Sbostic /*                                                                       */
28*45679Sbostic /*  Author:		Arthur Berggreen                                 */
29*45679Sbostic /*                                                                       */
30*45679Sbostic /*  Project:		ACP6100 (UPB with HDLC firmware)                 */
31*45679Sbostic /*                                                                       */
32*45679Sbostic /*  Function:		4.2BSD UNIX Network Interface Driver for ACP6100 */
33*45679Sbostic /*                                                                       */
34*45679Sbostic /*  Components:		if_acp.c, if_acpreg.h, if_acpvar.h               */
35*45679Sbostic /*                                                                       */
36*45679Sbostic /*  Revision History:                                                    */
37*45679Sbostic /*                                                                       */
38*45679Sbostic /*    16-AUG-1985  Clare Russ:  add fileheader and comments              */
39*45679Sbostic /*    24-SEP-1985  Clare Russ:  modify for socket ioctl user interface   */
40*45679Sbostic /*    06-NOV-1985  Clare Russ:  modify for socket ioctl under TWG        */
41*45679Sbostic /*    11-NOV-1985  Clare Russ:  Add a call to acpreset() in acpioctl()   */
42*45679Sbostic /*         before processing socket ioctl to clear COMREGs.  In the      */
43*45679Sbostic /*         acpinit() routine, avoid redundant allocation of UMRs by      */
44*45679Sbostic /*         doing so only if the front end is not RUNNING.                */
45*45679Sbostic /*    14-NOV-1985  Clare Russ:  Trace if_ubainit failure:  happens with  */
46*45679Sbostic /*         TWG, not 4.2BSD.                                              */
47*45679Sbostic /*    21-NOV-1985  Clare Russ:  Modify for compliance with the new       */
48*45679Sbostic /*         Control Interface (CIF) and Access Path Allocation Protocol   */
49*45679Sbostic /*         (APAP).  The CIF requires that Control Interface Messages     */
50*45679Sbostic /*         (CIMs) are exchanged between the host and front end in        */
51*45679Sbostic /*         command/response pairs.  The APAP requires that the control   */
52*45679Sbostic /*         and data paths be established (via exchange of CIMs between   */
53*45679Sbostic /*         the host and the front end) prior to use.                     */
54*45679Sbostic /*    26-NOV-1985  Clare Russ:  Add ability to bring down line in        */
55*45679Sbostic /*         response to 'acpconfig' command.                              */
56*45679Sbostic /*    27-NOV-1985  Clare Russ:  Add ability to specify DTE or DCE mode   */
57*45679Sbostic /*         in response to 'acpconfig' command.                           */
58*45679Sbostic /*    02-DEC-1985  Clare Russ:  Add ability to set baud rate (external   */
59*45679Sbostic /*         clock) or set internal clock.                                 */
60*45679Sbostic /*    14-JAN-1986  Clare Russ:  Add acpinit call to acpioctl under       */
61*45679Sbostic /*         SIOCSIFADDR processing                                        */
62*45679Sbostic /*    21-JAN-1986  Clare Russ:  Flush pending I/O in acpreset, free the  */
63*45679Sbostic /*         mbufs                                                         */
64*45679Sbostic /*    30-MAY-1986  Clare Russ:  Update MPCP host request subfunction     */
65*45679Sbostic /*         values, fix baud rate values in baud_rate[], change default   */
66*45679Sbostic /*         clock source from internal to external (in ssp_msg[])         */
67*45679Sbostic /*    24-JUL-1986  Clare Russ:  In supr_msg() print out RSF field when   */
68*45679Sbostic /*         path allocation or deallocation fails                         */
69*45679Sbostic /*    23-FEB-1987  Jeff Berkowitz: port to 4.3BSD by adding #ifdefs for  */
70*45679Sbostic /*	   new interface address formats, trapping 0 length mbufs, etc.  */
71*45679Sbostic /*    08-JAN-1988  Brad Engstrom:  port to ULTRIX 2.0 by using the       */
72*45679Sbostic /*	   UBAUVII (ultrix 2.0) and MVAX (microvax) defines to handle    */
73*45679Sbostic /*         special cases.  These cases are:                              */
74*45679Sbostic /*         1) not declaring br, cvec as value-result in the probe routine*/
75*45679Sbostic /*         2) using 0x17 as the ipl for a microvax                       */
76*45679Sbostic /*         3) in all other cases the ULTRIX drivers behaves like a 4.3   */
77*45679Sbostic /*            driver.                                                    */
78*45679Sbostic /*                                                                       */
79*45679Sbostic /*  Usage Notes:                                                         */
80*45679Sbostic /*                                                                       */
81*45679Sbostic /*    device acp0 at uba0 csr 016700 flags 0 vector acpinta acpintb      */
82*45679Sbostic /*                                                                       */
83*45679Sbostic /*         The 'flags' value is nonzero in the configuration file        */
84*45679Sbostic /*         for TWG, and may be left as zero in the configuration         */
85*45679Sbostic /*         file for UNIX 4.2 BSD.                                        */
86*45679Sbostic /*                                                                       */
87*45679Sbostic /*  Application Notes:	                                                 */
88*45679Sbostic /*                                                                       */
89*45679Sbostic /*    Refer to the Installation Instructions and the UNIX Programmer's   */
90*45679Sbostic /*    Manual page which are on the driver distribution medium.           */
91*45679Sbostic /*                                                                       */
92*45679Sbostic /*                                                                       */
93*45679Sbostic /*************************************************************************/
94*45679Sbostic 
95*45679Sbostic 
96*45679Sbostic /* #define ACPDEBUG 1	/* define for debug printf statements */
97*45679Sbostic 
98*45679Sbostic #ifdef ACPDEBUG
99*45679Sbostic int acp_debug = 0;	/* acp_debug is 1-8 for increasing verbosity */
100*45679Sbostic #endif ACPDEBUG
101*45679Sbostic 
102*45679Sbostic 
103*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
104*45679Sbostic /*%%                                                                   %%*/
105*45679Sbostic /*%%                          INCLUDE FILES                            %%*/
106*45679Sbostic /*%%                                                                   %%*/
107*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
108*45679Sbostic 
109*45679Sbostic /* The number of ACP 6100s in the system is defined in the configuration */
110*45679Sbostic /* file in /sys/conf.  When 'config' is run, the file acp.h is created   */
111*45679Sbostic /* with the definition of NACP, the number of ACP 6100s in the system.   */
112*45679Sbostic 
113*45679Sbostic #include "acp.h"
114*45679Sbostic #if NACP > 0
115*45679Sbostic #include "../machine/pte.h"
116*45679Sbostic 
117*45679Sbostic #include "../h/param.h"
118*45679Sbostic #include "../h/systm.h"
119*45679Sbostic #include "../h/mbuf.h"
120*45679Sbostic #include "../h/buf.h"
121*45679Sbostic #include "../h/protosw.h"
122*45679Sbostic #include "../h/socket.h"
123*45679Sbostic #include "../h/vmmac.h"
124*45679Sbostic #include "../h/errno.h"
125*45679Sbostic #include "../h/time.h"
126*45679Sbostic #include "../h/kernel.h"
127*45679Sbostic #include "../h/ioctl.h"
128*45679Sbostic 
129*45679Sbostic #include "../net/if.h"
130*45679Sbostic #include "../net/netisr.h"
131*45679Sbostic #include "../net/route.h"
132*45679Sbostic #include "../netinet/in.h"
133*45679Sbostic #include "../netinet/in_systm.h"
134*45679Sbostic #ifndef FOURTWO
135*45679Sbostic # include "../netinet/in_var.h"
136*45679Sbostic #endif
137*45679Sbostic #include "../netinet/ip.h"
138*45679Sbostic #include "../netinet/ip_var.h"
139*45679Sbostic 
140*45679Sbostic #include "../vax/cpu.h"
141*45679Sbostic #include "../vax/mtpr.h"
142*45679Sbostic #include "../vaxif/if_acpreg.h"
143*45679Sbostic #include "../vaxif/if_acpvar.h"
144*45679Sbostic #include "../vaxif/if_uba.h"
145*45679Sbostic #include "../vaxuba/ubareg.h"
146*45679Sbostic #include "../vaxuba/ubavar.h"
147*45679Sbostic 
148*45679Sbostic 
149*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
150*45679Sbostic /*%%                                                                   %%*/
151*45679Sbostic /*%%                        GLOBAL FUNCTIONS                           %%*/
152*45679Sbostic /*%%                                                                   %%*/
153*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
154*45679Sbostic 
155*45679Sbostic int acpprobe();
156*45679Sbostic int acpattach();
157*45679Sbostic int acpreset();
158*45679Sbostic int acpinit();
159*45679Sbostic int acpoutput();
160*45679Sbostic int acptimer();		/* currently no timer routine exists   */
161*45679Sbostic int acpioctl();
162*45679Sbostic int acpinta();
163*45679Sbostic int acpintb();
164*45679Sbostic int acpstart();
165*45679Sbostic 
166*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
167*45679Sbostic /*%%                                                                   %%*/
168*45679Sbostic /*%%                         LOCAL FUNCTIONS                           %%*/
169*45679Sbostic /*%%                                                                   %%*/
170*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
171*45679Sbostic 
172*45679Sbostic static void acp_alloc();	/* allocate control and data paths       */
173*45679Sbostic static void acp_init();		/* send Set System Parameters Message    */
174*45679Sbostic static void acp_iorq();
175*45679Sbostic static void start_chn();
176*45679Sbostic static void acp_data();
177*45679Sbostic static void acp_response();	/* send CIM response to the front end    */
178*45679Sbostic static void acp_supr();
179*45679Sbostic static void supr_msg();
180*45679Sbostic static void send_supr();
181*45679Sbostic 
182*45679Sbostic #ifdef ACPDEBUG
183*45679Sbostic static void prt_addr();
184*45679Sbostic static void prt_bytes();
185*45679Sbostic #endif ACPDEBUG
186*45679Sbostic 
187*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
188*45679Sbostic /*%%                                                                   %%*/
189*45679Sbostic /*%%                         LOCAL VARIABLES                           %%*/
190*45679Sbostic /*%%                                                                   %%*/
191*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
192*45679Sbostic 
193*45679Sbostic struct	uba_device *acpinfo[NACP];	/* ptrs to device info           */
194*45679Sbostic u_short	acpstd[] = { 0767000, 0 };	/* standard UNIBUS CSR addresses */
195*45679Sbostic struct	uba_driver acpdriver =		/* device driver info            */
196*45679Sbostic   {
197*45679Sbostic     acpprobe,				/* device probe routine */
198*45679Sbostic     0,					/* slave probe routine */
199*45679Sbostic     acpattach,				/* device attach routine */
200*45679Sbostic     0,					/* "dmago" routine */
201*45679Sbostic     acpstd,				/* device address */
202*45679Sbostic     "acp",				/* device name */
203*45679Sbostic     acpinfo				/* ptr to device info ptrs */
204*45679Sbostic   };
205*45679Sbostic 
206*45679Sbostic /* The alloc_msg array contains the Command Interface Message (CIM)    */
207*45679Sbostic /* for path allocation.  There are 12 bytes of header followed by 6    */
208*45679Sbostic /* bytes of command information                                        */
209*45679Sbostic 
210*45679Sbostic static u_char alloc_msg[] =
211*45679Sbostic   {
212*45679Sbostic     0x00,				/* reserved, must be zero      */
213*45679Sbostic     FAC_ALLOC,				/* front end ALLOC facility    */
214*45679Sbostic     0x00,				/* reserved, must be zero      */
215*45679Sbostic     CMD_ALLOC,				/* allocate path command       */
216*45679Sbostic     0x0f, 0x0a, 0x0c, 0x0e,		/* Command ID (CID)            */
217*45679Sbostic     0x00, 0x00, 0x00, 0x00,		/* Response/Status Field (RSF) */
218*45679Sbostic     0x00, ACP_SUPR,			/* Data Path Number (DPN)      */
219*45679Sbostic     0x00, FAC_HDLC,			/* front end HDLC facility     */
220*45679Sbostic     0x00, TYPE_CNTL			/* type of path:  control      */
221*45679Sbostic   };
222*45679Sbostic 
223*45679Sbostic 
224*45679Sbostic /* The dealloc_msg array contains the Command Interface Message (CIM)  */
225*45679Sbostic /* for path deallocation.  There are 12 bytes of header followed by 2  */
226*45679Sbostic /* bytes of command information                                        */
227*45679Sbostic 
228*45679Sbostic static u_char dealloc_msg[] =
229*45679Sbostic   {
230*45679Sbostic     0x00,				/* reserved, must be zero      */
231*45679Sbostic     FAC_ALLOC,				/* front end ALLOC facility    */
232*45679Sbostic     0x00,				/* reserved, must be zero      */
233*45679Sbostic     CMD_DEALLOC,			/* allocate path command       */
234*45679Sbostic     0x0c, 0x0a, 0x0f, 0x0e,		/* Command ID (CID)            */
235*45679Sbostic     0x00, 0x00, 0x00, 0x00,		/* Response/Status Field (RSF) */
236*45679Sbostic     0x00, ACP_SUPR,			/* Data Path Number (DPN)      */
237*45679Sbostic   };
238*45679Sbostic 
239*45679Sbostic 
240*45679Sbostic /* Table of baud rate values and the associated parameter for the Set  */
241*45679Sbostic /* System Parameters message, ssp_msg.  The second byte is nonzero for */
242*45679Sbostic /* valid baud rate divisors.                                           */
243*45679Sbostic 
244*45679Sbostic struct	baud	{
245*45679Sbostic 	char	b_value;
246*45679Sbostic 	u_char	parameter1;	/* first byte of baud rate setting  */
247*45679Sbostic 	u_char	parameter2;	/* second byte of baud rate setting */
248*45679Sbostic }	baud_rate[] =	{
249*45679Sbostic 	{ 1,	0x00, 	0x02 },
250*45679Sbostic 	{ 2,	0x00, 	0x03 },
251*45679Sbostic 	{ 3,	0x00, 	0x04 },
252*45679Sbostic 	{ 4,	0x00, 	0x08 },
253*45679Sbostic 	{ 5,	0x00, 	0x10 },
254*45679Sbostic 	{ 6,	0x00, 	0x28 },
255*45679Sbostic 	{ 7,	0x00, 	0x3e },
256*45679Sbostic 	{ 8,	0x00, 	0x47 },
257*45679Sbostic 	{ 9,	0x00, 	0x85 },
258*45679Sbostic 	{ 10,	0x00, 	0xd0 },
259*45679Sbostic 	{ 11,	0x01, 	0xa1 },
260*45679Sbostic 	{ 12,	0x03, 	0x41 },
261*45679Sbostic 	{ 13,	0x06,	0x83 },
262*45679Sbostic 	{ 14,	0x0d, 	0x05 },
263*45679Sbostic 	{ 0,	0,	0 },
264*45679Sbostic };
265*45679Sbostic 
266*45679Sbostic /* The ssp_msg array contains the Command Interface Message (CIM) for  */
267*45679Sbostic /* Setting HDLC System Paramters.  There are 12 bytes of header        */
268*45679Sbostic /* followed by the line number and parameter modification commands     */
269*45679Sbostic /* (PMCs).  The driver sends this CIM to the front end when kicked by  */
270*45679Sbostic /* the acpconfig program (via socket ioctl).  In future versions, the  */
271*45679Sbostic /* CIM won't be here in the driver, it will be passed to the driver.   */
272*45679Sbostic 
273*45679Sbostic u_char ssp_msg[] =
274*45679Sbostic   {
275*45679Sbostic     0x00,				/* reserved, must be zero      */
276*45679Sbostic     FAC_HDLC,				/* front end HDLC facility     */
277*45679Sbostic     0x00,				/* reserved, must be zero      */
278*45679Sbostic     CMD_SSP,				/* set HDCL system parameters  */
279*45679Sbostic     0x0b, 0x0e, 0x0e, 0x0f,		/* Command ID (CID)            */
280*45679Sbostic     0x00, 0x00, 0x00, 0x00,		/* Response/Status Field (RSF) */
281*45679Sbostic     0x00, 0x00,				/* HDLC Line Number (0)        */
282*45679Sbostic     LINK_DISABLE,			/* link disable                */
283*45679Sbostic     LINK_LOOPBACK,			/* loopback mode               */
284*45679Sbostic     LOOP_EXTERNAL,			/*   external loopback         */
285*45679Sbostic     DCE_OR_DTE,				/* specify DTE or DCE mode     */
286*45679Sbostic     DTE_MODE,				/*   DTE mode                  */
287*45679Sbostic     BAUD_CNTL,				/* baud rate divisor           */
288*45679Sbostic     0x00,				/*                             */
289*45679Sbostic     0x03,				/*  3 = 1.333 Mb/sec           */
290*45679Sbostic     IDLE_POLL,				/* idle poll selection         */
291*45679Sbostic     0x01,				/*  1 = on                     */
292*45679Sbostic     CLOCK_CNTL,				/* xmit clock selection        */
293*45679Sbostic     0x00,				/*  0 = external source        */
294*45679Sbostic     LINK_ENABLE				/* link enable                 */
295*45679Sbostic   };
296*45679Sbostic 
297*45679Sbostic /* The response_msg array contains the Command Interface Message (CIM) */
298*45679Sbostic /* response to be sent back to the front end in response to a CIM      */
299*45679Sbostic /* command for Frame Level Status from the front end.   The front end  */
300*45679Sbostic /* sends the Frame Level Status CIM command to the host when the frame */
301*45679Sbostic /* level status changes from up to down or vice versa.  In keeping     */
302*45679Sbostic /* with the philosophy with CIMs, they are always exchanged in command */
303*45679Sbostic /* response pairs.                                                     */
304*45679Sbostic 
305*45679Sbostic static u_char response_msg[] =
306*45679Sbostic   {
307*45679Sbostic     0x00,				/* reserved, must be zero      */
308*45679Sbostic     FAC_HDLC,				/* front end HDLC facility     */
309*45679Sbostic     0x00,				/* reserved, must be zero      */
310*45679Sbostic     RSP_FLUP,				/* Frame Level Status          */
311*45679Sbostic     0x00, 0x00, 0x00, 0x00,		/* Command ID (CID)            */
312*45679Sbostic     0x00, 0x00, 0x00, 0x00,		/* RSF is 0 for success        */
313*45679Sbostic     0x00, 0x00				/* HDLC Line Number  (0)       */
314*45679Sbostic   };
315*45679Sbostic 
316*45679Sbostic 
317*45679Sbostic /***********************************************************************\
318*45679Sbostic *									*
319*45679Sbostic *	Information for each device unit is maintained in an array	*
320*45679Sbostic *	of structures named acp_softc[].  The array is indexed by	*
321*45679Sbostic *	unit number.  Each entry includes the network interface		*
322*45679Sbostic *	structure (acp_if) used by the routing code to locate the	*
323*45679Sbostic *	interface,  an array of Logical	Channel control blocks which	*
324*45679Sbostic *	maintain information about each of the Logical Channels (LCNs)	*
325*45679Sbostic *	through which communication with the ACP is maintained, a queue *
326*45679Sbostic *	of I/O requests pending for the ACP, the UNIBUS interrupt	*
327*45679Sbostic *	vector for the unit and misc flags.  The Logical Channel	*
328*45679Sbostic *	Control blocks maintain information about the state of each	*
329*45679Sbostic *	LCN, a queue of outbound data, Half Duplex Channel (HDX) blocks	*
330*45679Sbostic *	used for queuing I/O requests to the ACP and an ifuba		*
331*45679Sbostic *	structure which records the UNIBUS resources being held by	*
332*45679Sbostic *	the LCN.							*
333*45679Sbostic *									*
334*45679Sbostic \***********************************************************************/
335*45679Sbostic 
336*45679Sbostic struct sioq		/* Start I/O queue head */
337*45679Sbostic   {
338*45679Sbostic     struct hdx_chan	*sq_head;	/* queue head */
339*45679Sbostic     struct hdx_chan	*sq_tail;	/* queue tail */
340*45679Sbostic   };
341*45679Sbostic 
342*45679Sbostic struct hdx_chan		/* HDX channel block */
343*45679Sbostic   {
344*45679Sbostic     struct hdx_chan	*hc_next;	/* link to next HDX channel */
345*45679Sbostic     u_char		hc_chan;	/* HDX channel number */
346*45679Sbostic     u_char		hc_adx;		/* address bits 17-16 */
347*45679Sbostic     u_short		hc_addr;	/* address bits 15-00 */
348*45679Sbostic     u_short		hc_cnt;		/* byte count */
349*45679Sbostic     u_char		hc_func;	/* I/O function */
350*45679Sbostic     u_char		hc_sbfc;	/* I/O subfunction */
351*45679Sbostic   };
352*45679Sbostic 
353*45679Sbostic struct acp_cb		/* Logical Channel control block */
354*45679Sbostic   {
355*45679Sbostic     u_char		dc_lcn;		/* LCN number */
356*45679Sbostic     struct ifqueue	dc_oq;		/* LCN output queue */
357*45679Sbostic     struct hdx_chan	dc_rchan;	/* LCN read HDX channel */
358*45679Sbostic     struct hdx_chan	dc_wchan;	/* LCN write HDX channel */
359*45679Sbostic     struct ifuba	dc_ifuba;	/* UNIBUS resources */
360*45679Sbostic     u_short		dc_flags;	/* misc flags */
361*45679Sbostic   };
362*45679Sbostic 
363*45679Sbostic struct acp_softc	/* device control structure */
364*45679Sbostic   {
365*45679Sbostic     struct ifnet	acp_if;		/* network-visible interface   */
366*45679Sbostic     struct acp_cb	acp_cb[NACPCH+1]; /* Logical Channel cntl blks */
367*45679Sbostic     struct sioq		acp_sioq;	/* start I/O queue             */
368*45679Sbostic     u_short		acp_vector;	/* UNIBUS interrupt vector     */
369*45679Sbostic     u_short		acp_flags;	/* ACP operational flag        */
370*45679Sbostic     u_char		acp_path;	/* path allocation flag        */
371*45679Sbostic     u_short		acp_maxout;	/* maximum IP message sent     */
372*45679Sbostic     u_short 		acp_maxin;	/* maximum IP message rcvd     */
373*45679Sbostic #ifndef FOURTWO
374*45679Sbostic     struct in_addr	acp_ipaddr;	/* local IP address */
375*45679Sbostic #endif
376*45679Sbostic   } acp_softc[NACP];
377*45679Sbostic 
378*45679Sbostic /* The acp_path flag indicates whether or not a path has been allocated */
379*45679Sbostic /* and also whether or not to call acp_init to send an ssp_msg to the   */
380*45679Sbostic /* front end:  acp_path = 1    indicates supervisory path is allocated  */
381*45679Sbostic /*             acp_path = 2    indicates data path is allocated         */
382*45679Sbostic /*             acp_path = 0x10 indicates acp_init should be called      */
383*45679Sbostic /*                             to send CIM ssp_msg to the front end     */
384*45679Sbostic 
385*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
386*45679Sbostic /*%%                                                             %%*/
387*45679Sbostic /*%%                   GLOBAL ROUTINES                           %%*/
388*45679Sbostic /*%%                                                             %%*/
389*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
390*45679Sbostic 
391*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
392*45679Sbostic /*%%                      ACPPROBE()                             %%*/
393*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
394*45679Sbostic /*                                                                 */
395*45679Sbostic /* Purpose:                                                        */
396*45679Sbostic /*                                                                 */
397*45679Sbostic /*  This routine probes the device to obtain the UNIBUS interrupt  */
398*45679Sbostic /*  vector.  Since the ACP is a soft vector device, we obtain an   */
399*45679Sbostic /*  unused vector from the uba structure and return that.  The ACP */
400*45679Sbostic /*  is given the vector and the board is reset.  In order to save  */
401*45679Sbostic /*  the vector in the device info structure, we place it in a      */
402*45679Sbostic /*  static temporary where the attach routine can find it and save */
403*45679Sbostic /*  it in the device info structure.  This is necessary because    */
404*45679Sbostic /*  probe only provides a pointer to the device and we have no     */
405*45679Sbostic /*  idea which unit is being referenced.  This works in 4.2BSD     */
406*45679Sbostic /*  because the attach routine is called immediately after a       */
407*45679Sbostic /*  successful probe.                                              */
408*45679Sbostic /*                                                                 */
409*45679Sbostic /*  Call:          acpprobe(reg)                                   */
410*45679Sbostic /*  Argument:      reg:  caddr_t address in virtual memory of the  */
411*45679Sbostic /*                        control-status register                  */
412*45679Sbostic /*  Returns:       length of register structure for ACP device     */
413*45679Sbostic /*  Called by:     network software, part of autoconfiguration on  */
414*45679Sbostic /*                 the VAX, the address of this routine is one of  */
415*45679Sbostic /*                 the fields of the uba_driver structure          */
416*45679Sbostic /*  Calls to:      nothing                                         */
417*45679Sbostic /*                                                                 */
418*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
419*45679Sbostic 
420*45679Sbostic static int savevec;			/* static variable for vector */
421*45679Sbostic 
422*45679Sbostic acpprobe(reg, ui)
423*45679Sbostic caddr_t reg;
424*45679Sbostic struct uba_device *ui;			/* TWG VAX/VMS ONLY! */
425*45679Sbostic   {
426*45679Sbostic #ifndef UBAUVII                         /* not for Ultrix 2.0 */
427*45679Sbostic     register int br, cvec;		/* r11, r10 value-result */
428*45679Sbostic #endif UBAUVII
429*45679Sbostic     register struct acpregs *addr = (struct acpregs *)reg;
430*45679Sbostic 
431*45679Sbostic #ifdef lint
432*45679Sbostic     br = 0; cvec = br; br = cvec;	/* these variables are value-result */
433*45679Sbostic #endif
434*45679Sbostic 
435*45679Sbostic #ifdef VAXVMS
436*45679Sbostic     cvec = savevec = ui->ui_flags & 0x1f8;	/* use flags from config file */
437*45679Sbostic #else
438*45679Sbostic     cvec = savevec = (uba_hd[numuba].uh_lastiv - 8) & ~7;
439*45679Sbostic     uba_hd[numuba].uh_lastiv = cvec;
440*45679Sbostic #endif VAXVMS
441*45679Sbostic 
442*45679Sbostic 					/* return a vector pair */
443*45679Sbostic 					/*   aligned on QUADWORD boundary */
444*45679Sbostic 
445*45679Sbostic 					/* cvec is the interrupt vector   */
446*45679Sbostic 					/*   address on the UNIBUS        */
447*45679Sbostic 
448*45679Sbostic 					/* br is the IPL of the device    */
449*45679Sbostic 					/*   when it interrupts           */
450*45679Sbostic 
451*45679Sbostic #ifdef MVAX
452*45679Sbostic     br = 0x17;				/* return bus level for a uVAX */
453*45679Sbostic #else
454*45679Sbostic     br = 0x15;				/* return bus level */
455*45679Sbostic #endif MVAX
456*45679Sbostic 
457*45679Sbostic     addr->req_flags = 0;		/* clear handshake flags */
458*45679Sbostic     addr->cmp_flags = 0;
459*45679Sbostic     addr->xfr_flags = 0;
460*45679Sbostic     addr->sys_stat = 0;
461*45679Sbostic     addr->sys_vect = cvec >> 2;		/* pass vector to ACP */
462*45679Sbostic     addr->csr = CSR_RESET;		/* reset the board */
463*45679Sbostic     addr->csr |= CSR_IENB;		/* enable status intr */
464*45679Sbostic 
465*45679Sbostic     return (sizeof(struct acpregs));
466*45679Sbostic   }
467*45679Sbostic 
468*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
469*45679Sbostic /*%%                      ACPATTACH()                            %%*/
470*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
471*45679Sbostic /*                                                                 */
472*45679Sbostic /*  Purpose:                                                       */
473*45679Sbostic /*                                                                 */
474*45679Sbostic /*  This routine attaches the device to the network software.  The */
475*45679Sbostic /*  network interface structure is filled in.  The device will be  */
476*45679Sbostic /*  initialized when the system is ready to accept packets.        */
477*45679Sbostic /*                                                                 */
478*45679Sbostic /*  Call:           acpattach(ui)                                  */
479*45679Sbostic /*  Argument:       ui:  ptr to the uba_device data structure      */
480*45679Sbostic /*  Returns:        nothing                                        */
481*45679Sbostic /*  Called by:      network software, part of network system       */
482*45679Sbostic /*                  configuration, identification to the network   */
483*45679Sbostic /*                  software,  the address of this routine is one  */
484*45679Sbostic /*                  of the fields of the uba_driver sturcture      */
485*45679Sbostic /*  Calls to:       if_attach()                                    */
486*45679Sbostic /*                                                                 */
487*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
488*45679Sbostic 
489*45679Sbostic acpattach(ui)
490*45679Sbostic struct uba_device *ui;
491*45679Sbostic   {
492*45679Sbostic     register struct acp_softc *ds = &acp_softc[ui->ui_unit];
493*45679Sbostic 
494*45679Sbostic     ds->acp_vector = savevec;		/* save vector from probe() */
495*45679Sbostic     ds->acp_if.if_unit = ui->ui_unit;	/* set unit number */
496*45679Sbostic     ds->acp_if.if_name = "acp";		/* set device name */
497*45679Sbostic     ds->acp_if.if_mtu = ACPMTU;		/* set max msg size */
498*45679Sbostic     ds->acp_if.if_init = acpinit;	/* set init routine addr */
499*45679Sbostic     ds->acp_if.if_ioctl = acpioctl;	/* set ioctl routine addr */
500*45679Sbostic     ds->acp_if.if_output = acpoutput;	/* set output routine addr */
501*45679Sbostic     ds->acp_if.if_start = acpstart;	/* set start routine addr */
502*45679Sbostic     ds->acp_if.if_reset = acpreset;	/* set reset routine addr */
503*45679Sbostic     if_attach(&ds->acp_if);		/* attach new network device */
504*45679Sbostic 					/*  add to list of "active"  */
505*45679Sbostic 					/*  interfaces, the argument */
506*45679Sbostic 					/*  passed locates the ifnet */
507*45679Sbostic 					/*  data structure           */
508*45679Sbostic   }
509*45679Sbostic 
510*45679Sbostic 
511*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
512*45679Sbostic /*%%                      ACPRESET()                             %%*/
513*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
514*45679Sbostic /*                                                                 */
515*45679Sbostic /*  Purpose:                                                       */
516*45679Sbostic /*                                                                 */
517*45679Sbostic /*      Reset of interface after UNIBUS reset.  If interface is on */
518*45679Sbostic /*      specified uba, reset its state.                            */
519*45679Sbostic /*                                                                 */
520*45679Sbostic /*  Call:              acpreset(unit, uban)                        */
521*45679Sbostic /*  Arguments:         unit:   ACP device unit number              */
522*45679Sbostic /*                     uban:   UNIBUS adapter number               */
523*45679Sbostic /*  Returns:           nothing                                     */
524*45679Sbostic /*  Called by:         network software, address of routine is     */
525*45679Sbostic /*                     defined in acp_if network interface struct  */
526*45679Sbostic /*  Calls to:          printf()                                    */
527*45679Sbostic /*                     IF_DEQUEUE()                                */
528*45679Sbostic /*                     m_freem()                                   */
529*45679Sbostic /*                                                                 */
530*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
531*45679Sbostic 
532*45679Sbostic acpreset(unit, uban)
533*45679Sbostic int unit, uban;
534*45679Sbostic   {
535*45679Sbostic     register struct uba_device *ui;	/* per "device" structure        */
536*45679Sbostic     register struct acpregs *addr;	/* ACP device register struct    */
537*45679Sbostic     register struct acp_cb *dc;
538*45679Sbostic     register struct mbuf *m;
539*45679Sbostic     register int lcn;
540*45679Sbostic 
541*45679Sbostic     if (unit >= NACP || (ui = acpinfo[unit]) == 0 || ui->ui_alive == 0 ||
542*45679Sbostic       ui->ui_ubanum != uban)
543*45679Sbostic 	return;
544*45679Sbostic 
545*45679Sbostic     printf("acp%d\n", unit);
546*45679Sbostic 
547*45679Sbostic     addr = (struct acpregs *)ui->ui_addr;  /* address of device in I/O space  */
548*45679Sbostic 
549*45679Sbostic     addr->req_flags = 0;		/* clear handshake flags, mailbox     */
550*45679Sbostic 					/*  flags for I/O requests            */
551*45679Sbostic     addr->cmp_flags = 0;		/* mailbox flags for I/O completion   */
552*45679Sbostic     addr->xfr_flags = 0;		/* mailbox flags for I/O transfer     */
553*45679Sbostic 					/*  requests                          */
554*45679Sbostic     addr->sys_stat = 0;			/* mailbox flags for system status    */
555*45679Sbostic     addr->sys_vect = acp_softc[unit].acp_vector >> 2;  /* pass base interrupt */
556*45679Sbostic 					/*  vector to ACP                     */
557*45679Sbostic     addr->csr = CSR_RESET;		/* reset the board                    */
558*45679Sbostic     addr->csr |= CSR_IENB;		/* enable status intr                 */
559*45679Sbostic     acp_softc[unit].acp_flags = 0;	/* clear ACP operational flag         */
560*45679Sbostic     acp_softc[unit].acp_path = 0;	/* clear path allocation flag         */
561*45679Sbostic 
562*45679Sbostic     dc = acp_softc[unit].acp_cb;	/* flush any queued output data */
563*45679Sbostic     for(lcn = 0; lcn <= NACPCH; lcn++)	/* for all LCN's ... */
564*45679Sbostic     {
565*45679Sbostic         while(dc->dc_oq.ifq_len)
566*45679Sbostic             {
567*45679Sbostic                 IF_DEQUEUE(&dc->dc_oq, m);
568*45679Sbostic                 m_freem(m);
569*45679Sbostic             }
570*45679Sbostic         dc++;
571*45679Sbostic     }
572*45679Sbostic 
573*45679Sbostic   }
574*45679Sbostic 
575*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
576*45679Sbostic /*%%                      ACPINIT()                              %%*/
577*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
578*45679Sbostic /*                                                                 */
579*45679Sbostic /*  Purpose:                                                       */
580*45679Sbostic /*                                                                 */
581*45679Sbostic /*    This routine initializes the interface for operation.  The   */
582*45679Sbostic /*    device control blocks are initialized, UNIBUS resources are  */
583*45679Sbostic /*    allocated and an initialization message is sent to the ACP.  */
584*45679Sbostic /*                                                                 */
585*45679Sbostic /*  Call:             acpinit(unit)                                */
586*45679Sbostic /*  Argument:         unit:  ACP device unit number                */
587*45679Sbostic /*  Returns:          nothing                                      */
588*45679Sbostic /*  Called by:        network software, address of this routine is */
589*45679Sbostic /*                    defined in acp_if network interface struct   */
590*45679Sbostic /*                    acpioctl()                                   */
591*45679Sbostic /*                    acpintb()                                    */
592*45679Sbostic /*  Calls to:         in_netof() return the network number from    */
593*45679Sbostic /*                               internet address                  */
594*45679Sbostic /*                    if_ubainit()                                 */
595*45679Sbostic /*                    btoc()                                       */
596*45679Sbostic /*                    splimp()                                     */
597*45679Sbostic /*                    acp_ioreq()                                  */
598*45679Sbostic /*                    acp_alloc()                                  */
599*45679Sbostic /*                    acp_init()                                   */
600*45679Sbostic /*                    splx()                                       */
601*45679Sbostic /*                    if_rtinit()                                  */
602*45679Sbostic /*                                                                 */
603*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
604*45679Sbostic 
605*45679Sbostic acpinit(unit)
606*45679Sbostic int unit;
607*45679Sbostic   {
608*45679Sbostic     register struct acp_softc *ds = &acp_softc[unit];
609*45679Sbostic     register struct acp_cb *dc;
610*45679Sbostic     register struct uba_device *ui = acpinfo[unit];
611*45679Sbostic #ifdef FOURTWO
612*45679Sbostic     struct sockaddr_in *sin;
613*45679Sbostic #else
614*45679Sbostic     struct ifaddr *ifa = ds->acp_if.if_addrlist;
615*45679Sbostic #endif
616*45679Sbostic     int lcn, s;
617*45679Sbostic 
618*45679Sbostic #ifdef ACPDEBUG
619*45679Sbostic if (acp_debug > 0)
620*45679Sbostic   {
621*45679Sbostic       printf("acp%d: acpinit()\n", unit);
622*45679Sbostic   }
623*45679Sbostic #endif ACPDEBUG
624*45679Sbostic 
625*45679Sbostic #ifdef FOURTWO
626*45679Sbostic     sin = (struct sockaddr_in *)&ds->acp_if.if_addr;
627*45679Sbostic     if (in_netof(sin->sin_addr) == 0)
628*45679Sbostic #else
629*45679Sbostic ifa = ds->acp_if.ifaddrlist;
630*45679Sbostic #ifdef AF_LINK
631*45679Sbostic for (; ifa; ifa = ifa->ifa_next)
632*45679Sbostic     if (ifa->ifa_addr->sa_family != AF_LINK)
633*45679Sbostic 	break;
634*45679Sbostic #endif
635*45679Sbostic if (    ifa == 0)    /* if we have no internet addr */
636*45679Sbostic #endif
637*45679Sbostic 	return;
638*45679Sbostic     if ((ds->acp_flags & ACPF_OK) == 0)	/* or if ACP not operational */
639*45679Sbostic 	return;				/*   don't init */
640*45679Sbostic 
641*45679Sbostic 
642*45679Sbostic     dc = ds->acp_cb;			/* setup ptr to first LCN cntl block */
643*45679Sbostic 
644*45679Sbostic     for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++)	/* for all LCN's ... */
645*45679Sbostic       {
646*45679Sbostic     	dc->dc_lcn = lcn;		/* record LCN */
647*45679Sbostic 
648*45679Sbostic 		/* init LCN output queue */
649*45679Sbostic 
650*45679Sbostic     	dc->dc_oq.ifq_head = (struct mbuf *)0;
651*45679Sbostic     	dc->dc_oq.ifq_tail = (struct mbuf *)0;
652*45679Sbostic     	dc->dc_oq.ifq_len = 0;
653*45679Sbostic     	dc->dc_oq.ifq_maxlen = ACP_OQMAX;
654*45679Sbostic     	dc->dc_oq.ifq_drops = 0;
655*45679Sbostic 
656*45679Sbostic     		/* init HDX channels */
657*45679Sbostic 
658*45679Sbostic     	dc->dc_rchan.hc_next = (struct hdx_chan *)0;
659*45679Sbostic     	dc->dc_rchan.hc_chan = lcn * 2;
660*45679Sbostic     	dc->dc_wchan.hc_next = (struct hdx_chan *)0;
661*45679Sbostic     	dc->dc_wchan.hc_chan = (lcn * 2) + 1;
662*45679Sbostic 
663*45679Sbostic     		/* init UNIBUS resources, allocate UNIBUS map registers */
664*45679Sbostic 
665*45679Sbostic     	if ((ds->acp_if.if_flags & IFF_RUNNING) == 0)
666*45679Sbostic           {
667*45679Sbostic     	    if (if_ubainit(&dc->dc_ifuba, ui->ui_ubanum,
668*45679Sbostic     	      0, (int)btoc(ACPMTU)) == 0)
669*45679Sbostic     	      {
670*45679Sbostic     	        printf("acp%d: failed getting UBA resources for lcn %d\n",
671*45679Sbostic     		  unit, lcn);
672*45679Sbostic     	        ds->acp_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
673*45679Sbostic     	        return;
674*45679Sbostic     	      }
675*45679Sbostic 	  }
676*45679Sbostic     	dc->dc_flags = 0;		/* initialize flags */
677*45679Sbostic 
678*45679Sbostic 	dc++;				/* point at next cntl blk */
679*45679Sbostic       }
680*45679Sbostic 
681*45679Sbostic     ds->acp_sioq.sq_head = (struct hdx_chan *)0;
682*45679Sbostic     ds->acp_sioq.sq_tail = (struct hdx_chan *)0;
683*45679Sbostic     ds->acp_if.if_flags |= IFF_RUNNING;
684*45679Sbostic 
685*45679Sbostic     s = splimp();			/* disable interrupts        */
686*45679Sbostic 
687*45679Sbostic     dc = ds->acp_cb;			/* setup ptr to first LCN cntl block */
688*45679Sbostic 
689*45679Sbostic     for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++)	/* issue reads on all LCNs */
690*45679Sbostic       {
691*45679Sbostic     	acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
692*45679Sbostic 	dc++;
693*45679Sbostic       }
694*45679Sbostic 
695*45679Sbostic 	/* if not already established, allocate control and data paths  */
696*45679Sbostic 
697*45679Sbostic     if ((ds->acp_path & ACP_SUPR) == 0)
698*45679Sbostic         acp_alloc(ds, TYPE_CNTL);	/* allocate control path  */
699*45679Sbostic     if ((ds->acp_path & ACP_DATA) == 0)
700*45679Sbostic         acp_alloc(ds, TYPE_DATA);	/* allocate data path     */
701*45679Sbostic 
702*45679Sbostic     if ((ds->acp_path & INIT_OK) == INIT_OK)
703*45679Sbostic       {
704*45679Sbostic         acp_init(ds);			/* init the ACP, if ioctl to do so */
705*45679Sbostic     	ds->acp_path &= ~INIT_OK;	/* turn off flag for acpinit() */
706*45679Sbostic       }
707*45679Sbostic 
708*45679Sbostic     splx(s);				/* enable interrupts        */
709*45679Sbostic 
710*45679Sbostic #ifdef FOURTWO
711*45679Sbostic     if_rtinit(&ds->acp_if, RTF_UP);	/* initialize the routing table entry */
712*45679Sbostic 					/*  according to the network, args    */
713*45679Sbostic 					/*  are the addr of the ifnet struct  */
714*45679Sbostic 					/*  and RTF_UP means the route is     */
715*45679Sbostic 					/*  useable                           */
716*45679Sbostic #endif
717*45679Sbostic   }
718*45679Sbostic 
719*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
720*45679Sbostic /*%%                      ACPOUTPUT()                            %%*/
721*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
722*45679Sbostic /*                                                                 */
723*45679Sbostic /*  Purpose:                                                       */
724*45679Sbostic /*                                                                 */
725*45679Sbostic /*   This routine is called by the network software when it has an */
726*45679Sbostic /*   IP datagram to send out this interface.  The datagtram is     */
727*45679Sbostic /*   queued for output on that LCN.                                */
728*45679Sbostic /*                                                                 */
729*45679Sbostic /*  Call:            acpoutput(ifp, m0, dst)                       */
730*45679Sbostic /*  Arguments:       ifp:  locates the network interface, ifnet    */
731*45679Sbostic /*                   m0:   locates an mbuf buffer                  */
732*45679Sbostic /*                   dst:  is the socket destination address       */
733*45679Sbostic /*  Returns:         0 for success, or one of following nonzero    */
734*45679Sbostic /*                        error indications:                       */
735*45679Sbostic /*                               ENETDOWN                          */
736*45679Sbostic /*                               EAFNOSUPPORT                      */
737*45679Sbostic /*                               ENOBUFS                           */
738*45679Sbostic /*  Called by:     network software, address of this routine is    */
739*45679Sbostic /*                 defined in the acp_if network interface struct  */
740*45679Sbostic /*  Calls to:      printf()                                        */
741*45679Sbostic /*                 mfreem()                                        */
742*45679Sbostic /*                 splimp()                                        */
743*45679Sbostic /*                 IF_QFULL()                                      */
744*45679Sbostic /*                 IF_DROP()                                       */
745*45679Sbostic /*                 splx()                                          */
746*45679Sbostic /*                 IF_ENQUEUE()                                    */
747*45679Sbostic /*                 m_freem()                                       */
748*45679Sbostic /*                 acp_start()                                     */
749*45679Sbostic /*                                                                 */
750*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
751*45679Sbostic 
752*45679Sbostic acpoutput(ifp, m0, dst)
753*45679Sbostic struct ifnet *ifp;		/* network interface          */
754*45679Sbostic struct mbuf *m0;		/* buffer                     */
755*45679Sbostic struct sockaddr_in *dst;	/* socket destination address */
756*45679Sbostic   {
757*45679Sbostic     register struct mbuf *m = m0;
758*45679Sbostic     register struct acp_softc *ds = &acp_softc[ifp->if_unit];
759*45679Sbostic     register struct acp_cb *dc;
760*45679Sbostic     register struct ifqueue *oq;
761*45679Sbostic     struct mbuf *prev;
762*45679Sbostic     int s;
763*45679Sbostic 
764*45679Sbostic     if ((ds->acp_if.if_flags & IFF_UP) == 0)
765*45679Sbostic 	return (ENETDOWN);
766*45679Sbostic 
767*45679Sbostic     switch (dst->sin_family)
768*45679Sbostic       {
769*45679Sbostic 
770*45679Sbostic #ifdef INET
771*45679Sbostic     case AF_INET:		/* address format of protocol family */
772*45679Sbostic 				/*  this is the internet:  TCP, UDP, */
773*45679Sbostic 				/*  ICMP, IP, etc.                   */
774*45679Sbostic 	break;
775*45679Sbostic #endif INET
776*45679Sbostic 
777*45679Sbostic     default:
778*45679Sbostic 	printf("acp%d: can't handle af%d\n", ifp->if_unit,
779*45679Sbostic 	    dst->sin_family);
780*45679Sbostic 	m_freem(m0);
781*45679Sbostic 	return (EAFNOSUPPORT);
782*45679Sbostic       }
783*45679Sbostic 
784*45679Sbostic 
785*45679Sbostic #ifdef ACPDEBUG
786*45679Sbostic if (acp_debug > 6)
787*45679Sbostic   {
788*45679Sbostic       printf("acpoutput(): dst = ");
789*45679Sbostic       prt_addr(dst->sin_addr);
790*45679Sbostic       printf("\n");
791*45679Sbostic   }
792*45679Sbostic #endif ACPDEBUG
793*45679Sbostic 
794*45679Sbostic     /* In 4.3, the IP code may pass mbuf chains with 0-length mbufs */
795*45679Sbostic     /* This causes "transfer count = 0" messages and might even     */
796*45679Sbostic     /* cause actual garbage data transmission if the mbuf is at the */
797*45679Sbostic     /* end of the chain (we don't think it ever will be, but one    */
798*45679Sbostic     /* can't be too sure...so we scan the chain first).		    */
799*45679Sbostic     /* WE DO ASSUME that there is at least one nonempty mbuf!	    */
800*45679Sbostic 
801*45679Sbostic     while (m0->m_len == 0)
802*45679Sbostic     {
803*45679Sbostic 	m = m0;
804*45679Sbostic 	m0 = m0->m_next;
805*45679Sbostic 	m->m_next = 0;
806*45679Sbostic 	m_freem (m);
807*45679Sbostic     }
808*45679Sbostic     /* Now we know the first mbuf (at m0)  is not zero length	    */
809*45679Sbostic     prev = m0;
810*45679Sbostic     m = m0->m_next;
811*45679Sbostic     while (m)
812*45679Sbostic     {
813*45679Sbostic 	if (m->m_len == 0)
814*45679Sbostic 	{
815*45679Sbostic 	    prev->m_next = m->m_next;
816*45679Sbostic 	    m->m_next = 0;
817*45679Sbostic 	    m_freem (m);
818*45679Sbostic 	    m = prev->m_next;
819*45679Sbostic 	}
820*45679Sbostic 	else
821*45679Sbostic 	{
822*45679Sbostic 	    prev = m;
823*45679Sbostic 	    m = m->m_next;
824*45679Sbostic 	}
825*45679Sbostic     }
826*45679Sbostic     m = m0;			/* reset m to beginning of modified chain */
827*45679Sbostic 
828*45679Sbostic     s = splimp();		/* disable interrupts  */
829*45679Sbostic 
830*45679Sbostic     dc = &(ds->acp_cb[ACP_DATA]);	/*   data channel          */
831*45679Sbostic     oq = &(dc->dc_oq);			/*   point to output queue */
832*45679Sbostic     if (IF_QFULL(oq))			/*   if q full */
833*45679Sbostic       {
834*45679Sbostic 	IF_DROP(oq);			/*     drop the data */
835*45679Sbostic 	m_freem(m);
836*45679Sbostic 	ds->acp_if.if_collisions++;
837*45679Sbostic 	splx(s);
838*45679Sbostic 	return (ENOBUFS);
839*45679Sbostic       }
840*45679Sbostic     IF_ENQUEUE(oq, m);			/*   otherwise queue it */
841*45679Sbostic     acp_start(ds, dc);			/*   and try to output  */
842*45679Sbostic     splx(s);				/*   enable interrupts  */
843*45679Sbostic     return (0);				/*   successful return  */
844*45679Sbostic   }
845*45679Sbostic 
846*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
847*45679Sbostic /*%%                      ACPIOCTL()                             %%*/
848*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
849*45679Sbostic /*                                                                 */
850*45679Sbostic /*  Purpose:                                                       */
851*45679Sbostic /*                                                                 */
852*45679Sbostic /*   This routine processes device dependent ioctl's.  Supported   */
853*45679Sbostic /*   ioctls set the host's internet address for this network       */
854*45679Sbostic /*   interface, or send CIMs (Command Interface Messages) to the   */
855*45679Sbostic /*   ACP (ie to bring up the line).  The logic for setting the     */
856*45679Sbostic /*   interface address must remain compatible with both ifconfig   */
857*45679Sbostic /*   and acpconfig programs.                                       */
858*45679Sbostic /*                                                                 */
859*45679Sbostic /*  Call:            acpioctl(ifp, cmd, data)                      */
860*45679Sbostic /*  Argument:        ifp:   pointer to the network interface data  */
861*45679Sbostic /*                               structure, ifnet                  */
862*45679Sbostic /*                   cmd:   identifies the type of ioctl           */
863*45679Sbostic /*                   data:  information for the ioctl              */
864*45679Sbostic /*  Returns:         0 for success, or the nonzero error value:    */
865*45679Sbostic /*                                EINVAL invalid ioctl request     */
866*45679Sbostic /*  Called by:        network software, address of this routine is */
867*45679Sbostic /*                    defined in af_inet network interface struct  */
868*45679Sbostic /*  Calls to:         splimp()                                     */
869*45679Sbostic /*                    if_rtinit()                                  */
870*45679Sbostic /*                    in_netof()                                   */
871*45679Sbostic /*                    in_lnaof()                                   */
872*45679Sbostic /*                    acpinit()                                    */
873*45679Sbostic /*                    acpreset()                                   */
874*45679Sbostic /*                    printf()                                     */
875*45679Sbostic /*                    splx()                                       */
876*45679Sbostic /*                                                                 */
877*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
878*45679Sbostic 
879*45679Sbostic acpioctl(ifp, cmd, data)
880*45679Sbostic register struct ifnet *ifp;	/* network interface data structure      */
881*45679Sbostic int cmd;			/* type of ioctl request                 */
882*45679Sbostic caddr_t data;			/* address of data for ioctl request     */
883*45679Sbostic   {
884*45679Sbostic     register struct uba_device *ui = acpinfo[ifp->if_unit];
885*45679Sbostic     struct ifreq *ifr = (struct ifreq *)data;	/* ifreq is the interface */
886*45679Sbostic 				/* request struct used for socket ioctls  */
887*45679Sbostic     struct acp_softc *ds = &acp_softc[ifp->if_unit];
888*45679Sbostic     int s = splimp(), error = 0;	/* disable interrupts    */
889*45679Sbostic #ifdef FOURTWO
890*45679Sbostic     struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
891*45679Sbostic #else
892*45679Sbostic     struct ifaddr *ifa = ds->acp_if.if_addrlist;
893*45679Sbostic #endif
894*45679Sbostic 
895*45679Sbostic #ifdef ACPDEBUG
896*45679Sbostic if (acp_debug > 2)
897*45679Sbostic   {
898*45679Sbostic       printf("acp%d:  acpioctl()\n", ifp->if_unit);
899*45679Sbostic   }
900*45679Sbostic #endif ACPDEBUG
901*45679Sbostic 
902*45679Sbostic     switch (cmd)
903*45679Sbostic       {
904*45679Sbostic     case SIOCSIFADDR:			/* set ifnet address    */
905*45679Sbostic #ifdef FOURTWO
906*45679Sbostic 	if (ifp->if_flags & IFF_RUNNING)
907*45679Sbostic 	    if_rtinit(ifp, -1);		/* delete previous route */
908*45679Sbostic 	ifp->if_addr = *(struct sockaddr *)sin;
909*45679Sbostic 	ifp->if_net = in_netof(sin->sin_addr);
910*45679Sbostic 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
911*45679Sbostic 	if (ifp->if_flags & IFF_RUNNING)
912*45679Sbostic 	    if_rtinit(ifp, RTF_UP);	/* RTF_UP means route useable */
913*45679Sbostic 	else
914*45679Sbostic 	    acpinit(ifp->if_unit);
915*45679Sbostic #else
916*45679Sbostic         if (ifa->ifa_addr.sa_family != AF_INET)
917*45679Sbostic                 return(EINVAL);
918*45679Sbostic         if ((ifp->if_flags & IFF_RUNNING) == 0)
919*45679Sbostic                 acpinit(ifp->if_unit);
920*45679Sbostic         ds->acp_ipaddr = IA_SIN(ifa)->sin_addr;
921*45679Sbostic #endif
922*45679Sbostic 	break;
923*45679Sbostic 
924*45679Sbostic     case SIOCACPCONFIG:
925*45679Sbostic 	/* if not trying to bring down link (case '0') then trying to bring */
926*45679Sbostic 	/* it up, or reconfigure it -- don't do cmd unless internet address */
927*45679Sbostic 	/* has already been set                                             */
928*45679Sbostic 
929*45679Sbostic     	if (*(ifr->ifr_data) != '0' )
930*45679Sbostic 	{
931*45679Sbostic #ifdef FOURTWO
932*45679Sbostic             sin = (struct sockaddr_in *)&ds->acp_if.if_addr;
933*45679Sbostic             if (in_netof(sin->sin_addr) == 0)
934*45679Sbostic #else
935*45679Sbostic 	    if (ds->acp_if.if_addrlist == 0)
936*45679Sbostic #endif
937*45679Sbostic 	    {
938*45679Sbostic 	        printf("acp%d:  no internet address is set,", ifp->if_unit);
939*45679Sbostic 	        printf(" acpconfig command ignored\n");
940*45679Sbostic 	        goto exit;
941*45679Sbostic 	    }
942*45679Sbostic   	}
943*45679Sbostic   	acpreset(ifp->if_unit, ui->ui_ubanum); /* reset device */
944*45679Sbostic     	ds->acp_path |= INIT_OK;	/* set flag for acpinit() */
945*45679Sbostic 
946*45679Sbostic 	/* if command is set the baud rate, then set clocking for  */
947*45679Sbostic 	/* internal generation, and look up the value for the baud */
948*45679Sbostic 	/* rate divisor in the baud_rate table, put this value in  */
949*45679Sbostic 	/* the Set System Parameters message, ssp_msg              */
950*45679Sbostic 
951*45679Sbostic 	if ( (*(ifr->ifr_data) >= 1) && (*(ifr->ifr_data) <= 14) )
952*45679Sbostic 	{
953*45679Sbostic 	    register struct baud *p;
954*45679Sbostic 
955*45679Sbostic   	    ssp_msg[CLOCK_OFFSET] = INTERNAL_CLOCK;
956*45679Sbostic 
957*45679Sbostic 	    for (p = baud_rate; p->b_value; p++)
958*45679Sbostic 		{
959*45679Sbostic 	        if ((*(ifr->ifr_data) - p->b_value) == 0)
960*45679Sbostic 		    break;
961*45679Sbostic 		}
962*45679Sbostic 	    ssp_msg[BAUD_OFFSET] = p->parameter1;
963*45679Sbostic 	    ssp_msg[BAUD_OFFSET + 1] = p->parameter2;
964*45679Sbostic 	    if (p->b_value == 0)
965*45679Sbostic 	    {
966*45679Sbostic 		printf("acp%d: invalid value for baud rate\n", ifp->if_unit);
967*45679Sbostic 		goto exit;
968*45679Sbostic 	    }
969*45679Sbostic 	}
970*45679Sbostic 	else
971*45679Sbostic 	{
972*45679Sbostic     	    switch (*(ifr->ifr_data))
973*45679Sbostic             {
974*45679Sbostic     	        case '0':
975*45679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_DISABLE;
976*45679Sbostic         	    break;
977*45679Sbostic     	        case '1':
978*45679Sbostic   		    ssp_msg[LOOP_OFFSET] = LOOP_NONE;
979*45679Sbostic   		    ssp_msg[DTE_OFFSET] = DTE_MODE;
980*45679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
981*45679Sbostic 		    break;
982*45679Sbostic     	        case '2':
983*45679Sbostic   		    ssp_msg[LOOP_OFFSET] = LOOP_NONE;
984*45679Sbostic   		    ssp_msg[DTE_OFFSET] = DCE_MODE;
985*45679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
986*45679Sbostic 		    break;
987*45679Sbostic     	        case '3':
988*45679Sbostic   		    ssp_msg[LOOP_OFFSET] = LOOP_EXTERNAL;
989*45679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
990*45679Sbostic         	    break;
991*45679Sbostic     	        case '4':
992*45679Sbostic   		    ssp_msg[LOOP_OFFSET] = LOOP_INTERNAL;
993*45679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
994*45679Sbostic         	    break;
995*45679Sbostic     	        case 'b':
996*45679Sbostic   		    ssp_msg[CLOCK_OFFSET] = EXTERNAL_CLOCK;
997*45679Sbostic         	    break;
998*45679Sbostic                 default:
999*45679Sbostic 		    error = EINVAL;
1000*45679Sbostic 		    goto exit;
1001*45679Sbostic               }
1002*45679Sbostic 	 }
1003*45679Sbostic   	 acpinit(ifp->if_unit);		/* send ssp_msg to frontend */
1004*45679Sbostic          break;
1005*45679Sbostic 
1006*45679Sbostic     default:
1007*45679Sbostic 	error = EINVAL;
1008*45679Sbostic     }
1009*45679Sbostic 
1010*45679Sbostic exit:
1011*45679Sbostic     splx(s);				/* enable interrupts   */
1012*45679Sbostic     return (error);
1013*45679Sbostic   }
1014*45679Sbostic 
1015*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1016*45679Sbostic /*%%                      ACPINTA()                              %%*/
1017*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1018*45679Sbostic /*                                                                 */
1019*45679Sbostic /*  Purpose:                                                       */
1020*45679Sbostic /*                                                                 */
1021*45679Sbostic /*  This is the interrupt handler for I/O interrupts from the ACP  */
1022*45679Sbostic /*  The I/O mailboxes are scanned for handshake events to process. */
1023*45679Sbostic /*  The events are Transfer Request, I/O Request done and I/O      */
1024*45679Sbostic /*  Completion ready.  Note that the Transfer Request is not yet   */
1025*45679Sbostic /*  supported; an error message is printed if one is received.     */
1026*45679Sbostic /*                                                                 */
1027*45679Sbostic /*  Call:           acpinta(unit)                                  */
1028*45679Sbostic /*  Argument:       unit:  ACP device unit number                  */
1029*45679Sbostic /*  Returns:        nothing                                        */
1030*45679Sbostic /*  Called by:      network software, address of this routine is   */
1031*45679Sbostic /*                  defined in af_inet network interface struct    */
1032*45679Sbostic /*  Calls to:       printf()                                       */
1033*45679Sbostic /*                  start_chn()                                    */
1034*45679Sbostic /*                  acp_data()                                     */
1035*45679Sbostic /*                  acp_supr()                                     */
1036*45679Sbostic /*                                                                 */
1037*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1038*45679Sbostic 
1039*45679Sbostic acpinta(unit)
1040*45679Sbostic int unit;
1041*45679Sbostic   {
1042*45679Sbostic     register struct acpregs *addr = (struct acpregs *)acpinfo[unit]->ui_addr;
1043*45679Sbostic     register struct acp_softc *ds = &acp_softc[unit];
1044*45679Sbostic     register struct hdx_chan *hc;
1045*45679Sbostic     int chan, cc, cnt;
1046*45679Sbostic 
1047*45679Sbostic #ifdef ACPDEBUG
1048*45679Sbostic if (acp_debug > 7)
1049*45679Sbostic   {
1050*45679Sbostic       printf("acp%d: acpinta()\n", unit);
1051*45679Sbostic   }
1052*45679Sbostic #endif ACPDEBUG
1053*45679Sbostic 
1054*45679Sbostic     /* Figure out what kind of interrupt it was */
1055*45679Sbostic 
1056*45679Sbostic     if (addr->xfr_flags & FLAGS_RDY)	/* Transfer Request Mailbox */
1057*45679Sbostic       {
1058*45679Sbostic 	printf("acp%d: UNEXPECTED TRANSFER REQUEST!\n", unit);
1059*45679Sbostic 	addr->xfr_cnt = 0;
1060*45679Sbostic 	addr->xfr_flags = (addr->xfr_flags & ~FLAGS_RDY) | FLAGS_DON;
1061*45679Sbostic 	addr->csr |= CSR_INTRA;
1062*45679Sbostic       }
1063*45679Sbostic 
1064*45679Sbostic     if (addr->req_flags & FLAGS_DON)	/* I/O Request Mailbox  */
1065*45679Sbostic       {
1066*45679Sbostic     	/* try to start any queued i/o request */
1067*45679Sbostic 
1068*45679Sbostic     	if (ds->acp_sioq.sq_head = ds->acp_sioq.sq_head->hc_next)
1069*45679Sbostic     	  {
1070*45679Sbostic     	    start_chn(ds);
1071*45679Sbostic     	  }
1072*45679Sbostic 	else
1073*45679Sbostic 	  {
1074*45679Sbostic 	    addr->req_flags &= ~FLAGS_DON;
1075*45679Sbostic 	  }
1076*45679Sbostic       }
1077*45679Sbostic 
1078*45679Sbostic     if (addr->cmp_flags & FLAGS_RDY)	/* I/O Completion  Mailbox */
1079*45679Sbostic       {
1080*45679Sbostic 
1081*45679Sbostic 	/*
1082*45679Sbostic 	 * Get logical channel info.
1083*45679Sbostic 	 */
1084*45679Sbostic 	if ((chan = addr->cmp_chan) > NACPCH)
1085*45679Sbostic           {
1086*45679Sbostic 	    printf("acp%d: unknown channel, chan=%d\n", unit, chan);
1087*45679Sbostic 	    return;
1088*45679Sbostic 	  }
1089*45679Sbostic 
1090*45679Sbostic 	if (addr->cmp_flags & FLAGS_DIR)
1091*45679Sbostic     	    hc = &(ds->acp_cb[chan].dc_wchan);
1092*45679Sbostic 	else
1093*45679Sbostic     	    hc = &(ds->acp_cb[chan].dc_rchan);
1094*45679Sbostic 	cc = addr->cmp_stat;	/* Mailbox I/O completion status      */
1095*45679Sbostic 	cnt = addr->cmp_cnt;	/* Mailbox I/O completion byte count  */
1096*45679Sbostic 
1097*45679Sbostic     	switch (cc)	/* check for unsuccessful I/O completion status */
1098*45679Sbostic     	  {
1099*45679Sbostic     	case ACPIOCABT:
1100*45679Sbostic     	    printf("acp%d: I/O abort ", unit);
1101*45679Sbostic     	    goto daterr;
1102*45679Sbostic 
1103*45679Sbostic     	case ACPIOCERR:
1104*45679Sbostic     	    printf("acp%d: program error ", unit);
1105*45679Sbostic     	    goto daterr;
1106*45679Sbostic 
1107*45679Sbostic     	case ACPIOCOVR:
1108*45679Sbostic     	    printf("acp%d: overrun error ", unit);
1109*45679Sbostic     	    goto daterr;
1110*45679Sbostic 
1111*45679Sbostic     	case ACPIOCUBE:
1112*45679Sbostic     	    printf("acp%d: NXM timeout or UB parity error ", unit);
1113*45679Sbostic 
1114*45679Sbostic     	daterr:
1115*45679Sbostic     	    printf("chan=%d func=%x\n", chan, hc->hc_func);
1116*45679Sbostic     	    if (addr->cmp_flags & FLAGS_DIR)
1117*45679Sbostic     		ds->acp_if.if_oerrors++;
1118*45679Sbostic     	    else
1119*45679Sbostic     		ds->acp_if.if_ierrors++;
1120*45679Sbostic     	  }
1121*45679Sbostic 
1122*45679Sbostic     	/* was it supervisor or data traffic? */
1123*45679Sbostic 
1124*45679Sbostic     	if (chan > ACP_SUPR)
1125*45679Sbostic     	    acp_data(ds, hc, cc, cnt);
1126*45679Sbostic     	else
1127*45679Sbostic     	    acp_supr(ds, hc, cc, cnt, chan);  /* chan = ACP_ALLOC or ACP_SUPR */
1128*45679Sbostic 
1129*45679Sbostic     	/*
1130*45679Sbostic     	 * Ack the interrupt.  Fix the Mailbox Ready and Done bits:  set
1131*45679Sbostic          * DON bits, and clear RDY bits so mailbox may be reused.
1132*45679Sbostic     	 */
1133*45679Sbostic     	addr->cmp_flags = (addr->cmp_flags & ~FLAGS_RDY) | FLAGS_DON;
1134*45679Sbostic 	addr->csr |= CSR_INTRA;			/* enable interrupt "a" */
1135*45679Sbostic 
1136*45679Sbostic       }
1137*45679Sbostic   }
1138*45679Sbostic 
1139*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1140*45679Sbostic /*%%                      ACPINTB()                              %%*/
1141*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1142*45679Sbostic /*                                                                 */
1143*45679Sbostic /*  Purpose:                                                       */
1144*45679Sbostic /*                                                                 */
1145*45679Sbostic /*   This is the interrupt handler for system interrupts from the  */
1146*45679Sbostic /*   ACP.                                                          */
1147*45679Sbostic /*                                                                 */
1148*45679Sbostic /*  Call:             acpintb(unit)                                */
1149*45679Sbostic /*  Argument:         unit: ACP device unit number                 */
1150*45679Sbostic /*  Returns:          nothing                                      */
1151*45679Sbostic /*  Called by:        network software, address of this routine is */
1152*45679Sbostic /*                    defined in af_inet network interface struct  */
1153*45679Sbostic /*  Calls to:         printf()                                     */
1154*45679Sbostic /*                    acpinit()                                    */
1155*45679Sbostic /*                                                                 */
1156*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1157*45679Sbostic 
1158*45679Sbostic acpintb(unit)
1159*45679Sbostic int unit;
1160*45679Sbostic   {
1161*45679Sbostic     register struct acpregs *addr = (struct acpregs *)acpinfo[unit]->ui_addr;
1162*45679Sbostic     register struct acp_softc *ds = &acp_softc[unit];
1163*45679Sbostic 
1164*45679Sbostic #ifdef ACPDEBUG
1165*45679Sbostic if (acp_debug > 1)
1166*45679Sbostic   {
1167*45679Sbostic       printf("acp%d: acpintb()\n", unit);
1168*45679Sbostic   }
1169*45679Sbostic #endif ACPDEBUG
1170*45679Sbostic 
1171*45679Sbostic     if (ds->acp_flags & ACPF_OK)
1172*45679Sbostic       {
1173*45679Sbostic 	printf("acp%d: Unexpected System interrupt, status = %d\n",
1174*45679Sbostic 	    unit, addr->sys_stat);
1175*45679Sbostic 	addr->csr = 0;
1176*45679Sbostic 	printf("acp%d: DISABLED!\n", unit);
1177*45679Sbostic 	ds->acp_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
1178*45679Sbostic       }
1179*45679Sbostic     else
1180*45679Sbostic       {
1181*45679Sbostic 	if (addr->sys_stat != ACPSTAT_OK)
1182*45679Sbostic 	  {
1183*45679Sbostic 	    printf("acp%d: PWRUP Diagnostic failure = %d\n",
1184*45679Sbostic 		unit, addr->sys_stat);
1185*45679Sbostic 	    addr->csr = 0;
1186*45679Sbostic 	  }
1187*45679Sbostic 	else
1188*45679Sbostic 	  {
1189*45679Sbostic 	    ds->acp_flags |= ACPF_OK;
1190*45679Sbostic 	    addr->csr |= (CSR_IENA | CSR_DMAEN);
1191*45679Sbostic 	    acpinit(unit);
1192*45679Sbostic 	  }
1193*45679Sbostic       }
1194*45679Sbostic   }
1195*45679Sbostic 
1196*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1197*45679Sbostic /*%%                                                             %%*/
1198*45679Sbostic /*%%                   LOCAL  ROUTINES                           %%*/
1199*45679Sbostic /*%%                                                             %%*/
1200*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1201*45679Sbostic 
1202*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1203*45679Sbostic /*%%                      ACP_ALLOC()                            %%*/
1204*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1205*45679Sbostic /*                                                                 */
1206*45679Sbostic /*  Purpose:                                                       */
1207*45679Sbostic /*                                                                 */
1208*45679Sbostic /*   This routine allocates control or data paths.  Commands are   */
1209*45679Sbostic /*   sent (over DPN 0) from the host to the ALLOC facility on the  */
1210*45679Sbostic /*   front end to allocate the paths.  The ALLOC facility returns  */
1211*45679Sbostic /*   a response to the allocation command which indicates success  */
1212*45679Sbostic /*   or failure.  Note that DPN 0 is used only for the ALLOC       */
1213*45679Sbostic /*   commands, and is not a control path as it was been in the     */
1214*45679Sbostic /*   past.  The paths are symbolically defined as ACP_ALLOC,       */
1215*45679Sbostic /*   ACP_SUPR, and ACP_DATA for allocation messages, control       */
1216*45679Sbostic /*   messages, and data respectively.  The CID field indicates     */
1217*45679Sbostic /*   the data path number of the allocation command.  The CID      */
1218*45679Sbostic /*   is set here so that the response will have the same CID, and  */
1219*45679Sbostic /*   will therefore indicate to which path the response            */
1220*45679Sbostic /*   corresponds. (The CID is set in the command and must be       */
1221*45679Sbostic /*   returned, untouched, in the response.)                        */
1222*45679Sbostic /*                                                                 */
1223*45679Sbostic /*  Call:          acp_alloc(ds, type)                             */
1224*45679Sbostic /*  Argument:      ds:  pointer to ACP device control structure    */
1225*45679Sbostic /*                 type:  specifies if path is for control or data */
1226*45679Sbostic /*  Returns:       nothing                                         */
1227*45679Sbostic /*  Called by:     acpinit()                                       */
1228*45679Sbostic /*  Calls to:          MGET()                                      */
1229*45679Sbostic /*                     printf()                                    */
1230*45679Sbostic /*                     mtod()                                      */
1231*45679Sbostic /*                     bcopy()                                     */
1232*45679Sbostic /*                     sizeof()                                    */
1233*45679Sbostic /*                     IF_ENQUEUE()                                */
1234*45679Sbostic /*                     acp_start()                                 */
1235*45679Sbostic /*                                                                 */
1236*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1237*45679Sbostic 
1238*45679Sbostic static void acp_alloc(ds, type)
1239*45679Sbostic struct acp_softc *ds;
1240*45679Sbostic int type;
1241*45679Sbostic   {
1242*45679Sbostic     struct mbuf *m;
1243*45679Sbostic     register u_char *bp;
1244*45679Sbostic 
1245*45679Sbostic #ifdef ACPDEBUG
1246*45679Sbostic if (acp_debug > 4)
1247*45679Sbostic   {
1248*45679Sbostic       printf("acp%d: acp_alloc()\n", ds->acp_if.if_unit);
1249*45679Sbostic   }
1250*45679Sbostic #endif ACPDEBUG
1251*45679Sbostic 
1252*45679Sbostic     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get init buffer */
1253*45679Sbostic     if (m == 0)
1254*45679Sbostic       {
1255*45679Sbostic     	printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
1256*45679Sbostic     	return;
1257*45679Sbostic       }
1258*45679Sbostic 
1259*45679Sbostic 	/* modify the path allocation message to get a control path */
1260*45679Sbostic 	/* or a data path                                           */
1261*45679Sbostic 
1262*45679Sbostic     if (type == TYPE_CNTL)
1263*45679Sbostic       {
1264*45679Sbostic         alloc_msg[CID_OFFSET] = ACP_SUPR;	/* set CID for response */
1265*45679Sbostic         alloc_msg[DPN_OFFSET] = ACP_SUPR;	/* path number          */
1266*45679Sbostic         alloc_msg[TYPE_OFFSET] = TYPE_CNTL;	/* path type = control  */
1267*45679Sbostic       }
1268*45679Sbostic     else
1269*45679Sbostic       {
1270*45679Sbostic         alloc_msg[CID_OFFSET] = ACP_DATA;	/* set CID for response  */
1271*45679Sbostic         alloc_msg[DPN_OFFSET] = ACP_DATA;	/* path number           */
1272*45679Sbostic         alloc_msg[TYPE_OFFSET] = TYPE_DATA;	/* path type = data      */
1273*45679Sbostic       }
1274*45679Sbostic 
1275*45679Sbostic     bp = mtod(m, u_char *);		/* point to data section of mbuf */
1276*45679Sbostic 
1277*45679Sbostic     bcopy(alloc_msg, bp, sizeof(alloc_msg));  /* set sys params msg in mbuf */
1278*45679Sbostic 
1279*45679Sbostic #ifdef ACPDEBUG
1280*45679Sbostic if (acp_debug > 5)
1281*45679Sbostic   {
1282*45679Sbostic printf("acp_alloc():  ");
1283*45679Sbostic prt_bytes(bp, sizeof(alloc_msg));   /* print 12-byte header + data */
1284*45679Sbostic printf("\n");
1285*45679Sbostic   }
1286*45679Sbostic #endif ACPDEBUG
1287*45679Sbostic 
1288*45679Sbostic 
1289*45679Sbostic     m->m_len = sizeof(alloc_msg);		/* set msg length */
1290*45679Sbostic 
1291*45679Sbostic     IF_ENQUEUE(&(ds->acp_cb[ACP_ALLOC].dc_oq), m);	/* output queue   */
1292*45679Sbostic 
1293*45679Sbostic     acp_start(ds, &(ds->acp_cb[ACP_ALLOC]));	/* start ouput of data  */
1294*45679Sbostic   }
1295*45679Sbostic 
1296*45679Sbostic 
1297*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1298*45679Sbostic /*%%                      ACP_INIT()                             %%*/
1299*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1300*45679Sbostic /*                                                                 */
1301*45679Sbostic /*  Purpose:                                                       */
1302*45679Sbostic /*                                                                 */
1303*45679Sbostic /*   This routine builds and sends an initialization message to    */
1304*45679Sbostic /*   the ACP.  A canned Set System Parameters Message is sent to   */
1305*45679Sbostic /*   start HDLC.                                                   */
1306*45679Sbostic /*                                                                 */
1307*45679Sbostic /*  Call:          acp_init(ds)                                    */
1308*45679Sbostic /*  Argument:      ds:  pointer to ACP device control structure    */
1309*45679Sbostic /*  Returns:                nothing                                */
1310*45679Sbostic /*  Called by:         acpinit()                                   */
1311*45679Sbostic /*  Calls to:          MGET()                                      */
1312*45679Sbostic /*                     printf()                                    */
1313*45679Sbostic /*                     mtod()                                      */
1314*45679Sbostic /*                     bcopy()                                     */
1315*45679Sbostic /*                     sizeof()                                    */
1316*45679Sbostic /*                     IF_ENQUEUE()                                */
1317*45679Sbostic /*                     acp_start()                                 */
1318*45679Sbostic /*                                                                 */
1319*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1320*45679Sbostic 
1321*45679Sbostic static void acp_init(ds)
1322*45679Sbostic struct acp_softc *ds;
1323*45679Sbostic   {
1324*45679Sbostic     struct mbuf *m;
1325*45679Sbostic     register u_char *bp;
1326*45679Sbostic 
1327*45679Sbostic #ifdef ACPDEBUG
1328*45679Sbostic if (acp_debug > 5)
1329*45679Sbostic   {
1330*45679Sbostic       printf("acp%d: acp_init()\n", ds->acp_if.if_unit);
1331*45679Sbostic   }
1332*45679Sbostic #endif ACPDEBUG
1333*45679Sbostic 
1334*45679Sbostic     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get init buffer */
1335*45679Sbostic     if (m == 0)
1336*45679Sbostic       {
1337*45679Sbostic     	printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
1338*45679Sbostic     	return;
1339*45679Sbostic       }
1340*45679Sbostic 
1341*45679Sbostic     bp = mtod(m, u_char *);		/* point to data section of mbuf */
1342*45679Sbostic 
1343*45679Sbostic     bcopy(ssp_msg, bp, sizeof(ssp_msg));  /* put msg into mbuf */
1344*45679Sbostic 
1345*45679Sbostic #ifdef ACPDEBUG
1346*45679Sbostic if (acp_debug > 4)
1347*45679Sbostic   {
1348*45679Sbostic printf("acp_init():  ssp msg\n");
1349*45679Sbostic prt_bytes(bp, sizeof(ssp_msg));		/* print 12-byte header + data */
1350*45679Sbostic printf("\n");
1351*45679Sbostic   }
1352*45679Sbostic #endif ACPDEBUG
1353*45679Sbostic 
1354*45679Sbostic     m->m_len = sizeof(ssp_msg);		/* set msg length */
1355*45679Sbostic 
1356*45679Sbostic     IF_ENQUEUE(&(ds->acp_cb[ACP_SUPR].dc_oq), m);	/* output queue   */
1357*45679Sbostic 
1358*45679Sbostic     acp_start(ds, &(ds->acp_cb[ACP_SUPR]));	/* start ouput of data  */
1359*45679Sbostic   }
1360*45679Sbostic 
1361*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1362*45679Sbostic /*%%                      ACP_START()                            %%*/
1363*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1364*45679Sbostic /*                                                                 */
1365*45679Sbostic /*  Purpose:                                                       */
1366*45679Sbostic /*                                                                 */
1367*45679Sbostic /*    This routine attempts to start output of data queued on a    */
1368*45679Sbostic /*    specific LCN.  If the LCN was not already busy and data is   */
1369*45679Sbostic /*    available for output, the data is copied into the LCN's I/O  */
1370*45679Sbostic /*    buffer and an I/O request queued to the ACP.                 */
1371*45679Sbostic /*                                                                 */
1372*45679Sbostic /*  Call:              acpstart(ds, dc)                            */
1373*45679Sbostic /*  Arguments:         ds:  pointer to device control structure    */
1374*45679Sbostic /*                     dc:  pointer to the Logical Channel control */
1375*45679Sbostic /*                            block structure                      */
1376*45679Sbostic /*  Returns:           nothing                                     */
1377*45679Sbostic /*  Called by:         acpoutput()                                 */
1378*45679Sbostic /*                     acp_init()                                  */
1379*45679Sbostic /*                     acp_data()                                  */
1380*45679Sbostic /*                     acp_supr()                                  */
1381*45679Sbostic /*  Calls to:          IF_DEQUEUE()                                */
1382*45679Sbostic /*                     if_wubaput()                                */
1383*45679Sbostic /*                     acp_ioreqs()                                */
1384*45679Sbostic /*                                                                 */
1385*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1386*45679Sbostic 
1387*45679Sbostic static void acp_start(ds, dc)
1388*45679Sbostic register struct acp_softc *ds;
1389*45679Sbostic register struct acp_cb *dc;
1390*45679Sbostic   {
1391*45679Sbostic     register struct mbuf *m;
1392*45679Sbostic     int len;
1393*45679Sbostic 
1394*45679Sbostic     /*
1395*45679Sbostic      * If output isn't active, attempt to
1396*45679Sbostic      * start sending a new packet.
1397*45679Sbostic      */
1398*45679Sbostic 
1399*45679Sbostic #ifdef ACPDEBUG
1400*45679Sbostic if (acp_debug > 7)
1401*45679Sbostic   {
1402*45679Sbostic       printf("acp: acp_start()\n");
1403*45679Sbostic   }
1404*45679Sbostic #endif ACPDEBUG
1405*45679Sbostic 
1406*45679Sbostic     if ((dc->dc_flags & DC_OBUSY) || (dc->dc_oq.ifq_len == 0))
1407*45679Sbostic     	return;
1408*45679Sbostic 
1409*45679Sbostic     IF_DEQUEUE(&dc->dc_oq, m);	/* remove data from LCN output queue */
1410*45679Sbostic 
1411*45679Sbostic     len = if_wubaput(&dc->dc_ifuba, m);	/* copy data to mapped mem */
1412*45679Sbostic 
1413*45679Sbostic     if (len > ds->acp_maxout)
1414*45679Sbostic       {
1415*45679Sbostic 
1416*45679Sbostic #ifdef ACPDEBUG
1417*45679Sbostic if (acp_debug > 7)
1418*45679Sbostic   {
1419*45679Sbostic     printf("acp: %d byte msg sent.\n", len);
1420*45679Sbostic   }
1421*45679Sbostic #endif ACPDEBUG
1422*45679Sbostic 
1423*45679Sbostic 	ds->acp_maxout = len;
1424*45679Sbostic       }
1425*45679Sbostic 
1426*45679Sbostic     dc->dc_flags |= DC_OBUSY;
1427*45679Sbostic 
1428*45679Sbostic     acp_iorq(ds, dc, len, ACPWRT+ACPEOS);	/* build I/O request, enqueue */
1429*45679Sbostic   }
1430*45679Sbostic 
1431*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1432*45679Sbostic /*%%                      ACP_IORQ()                             %%*/
1433*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1434*45679Sbostic /*                                                                 */
1435*45679Sbostic /*  Purpose:                                                       */
1436*45679Sbostic /*                                                                 */
1437*45679Sbostic /*    This routine builds ACP I/O requests and queues them for     */
1438*45679Sbostic /*    delivery to the ACP. If the ACP I/O request comm regs are    */
1439*45679Sbostic /*    not busy, the I/O request is passed to the ACP.              */
1440*45679Sbostic /*                                                                 */
1441*45679Sbostic /*  Call:            acp_iorq(ds, dc, len, func)                   */
1442*45679Sbostic /*  Argument:        ds:   pointer to device control block struct  */
1443*45679Sbostic /*                   dc:   pointer to the Logical Channel control  */
1444*45679Sbostic /*                                block structure                  */
1445*45679Sbostic /*                   len:  byte count                              */
1446*45679Sbostic /*                   func: the function:  read or write            */
1447*45679Sbostic /*  Returns:         nothing                                       */
1448*45679Sbostic /*  Called by:         acpinit()                                   */
1449*45679Sbostic /*                     acp_start()                                 */
1450*45679Sbostic /*                     acp_data()                                  */
1451*45679Sbostic /*                     acp_supr()                                  */
1452*45679Sbostic /*  Calls to:          start_chn()                                 */
1453*45679Sbostic /*                                                                 */
1454*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1455*45679Sbostic 
1456*45679Sbostic static void acp_iorq(ds, dc, len, func)
1457*45679Sbostic struct acp_softc *ds;
1458*45679Sbostic struct acp_cb *dc;
1459*45679Sbostic int len, func;
1460*45679Sbostic   {
1461*45679Sbostic     register struct hdx_chan *hc;
1462*45679Sbostic     register int info;
1463*45679Sbostic 
1464*45679Sbostic 
1465*45679Sbostic #ifdef ACPDEBUG
1466*45679Sbostic if (acp_debug > 6)
1467*45679Sbostic       printf("acp: acp_iorq()\n");
1468*45679Sbostic #endif ACPDEBUG
1469*45679Sbostic 
1470*45679Sbostic     /* get appropriate UNIBUS mapping info */
1471*45679Sbostic 
1472*45679Sbostic     if ((func & FCN_MASK) == ACPRED)	/* read or write? */
1473*45679Sbostic       {
1474*45679Sbostic     	hc = &dc->dc_rchan;		/* read */
1475*45679Sbostic     	info = dc->dc_ifuba.ifu_r.ifrw_info;
1476*45679Sbostic       }
1477*45679Sbostic     else
1478*45679Sbostic       {
1479*45679Sbostic     	hc = &dc->dc_wchan;		/* write */
1480*45679Sbostic     	info = dc->dc_ifuba.ifu_w.ifrw_info;
1481*45679Sbostic       }
1482*45679Sbostic 
1483*45679Sbostic     /* set channel info */
1484*45679Sbostic 
1485*45679Sbostic     hc->hc_adx = (u_char)((info & 0x30000) >> 12);	/* address bits 17-16 */
1486*45679Sbostic     hc->hc_addr = (unsigned short)(info & 0xffff);	/* address bits 15-00 */
1487*45679Sbostic     hc->hc_cnt = len;					/* byte count         */
1488*45679Sbostic     hc->hc_func = (u_char)func;				/* I/O function       */
1489*45679Sbostic 
1490*45679Sbostic     if (dc->dc_lcn > ACP_SUPR)
1491*45679Sbostic         hc->hc_sbfc = SBFCN_DATA;		/* I/O subfunction for data */
1492*45679Sbostic     else
1493*45679Sbostic         hc->hc_sbfc = SBFCN_SUPR;		/* I/O subfunction for cntrl */
1494*45679Sbostic 
1495*45679Sbostic     /*
1496*45679Sbostic      * If ACP comm regs busy, queue start i/o for later.
1497*45679Sbostic      */
1498*45679Sbostic     if (ds->acp_sioq.sq_head)
1499*45679Sbostic       {
1500*45679Sbostic     	(ds->acp_sioq.sq_tail)->hc_next = hc;
1501*45679Sbostic     	ds->acp_sioq.sq_tail = hc;
1502*45679Sbostic     	hc->hc_next = 0;
1503*45679Sbostic     	return;
1504*45679Sbostic       }
1505*45679Sbostic 
1506*45679Sbostic     /* start i/o on channel now */
1507*45679Sbostic 
1508*45679Sbostic     ds->acp_sioq.sq_head = hc;
1509*45679Sbostic     ds->acp_sioq.sq_tail = hc;
1510*45679Sbostic     hc->hc_next = 0;
1511*45679Sbostic     start_chn(ds);
1512*45679Sbostic   }
1513*45679Sbostic 
1514*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1515*45679Sbostic /*%%                      START_CHN()                            %%*/
1516*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1517*45679Sbostic /*                                                                 */
1518*45679Sbostic /*  Purpose:                                                       */
1519*45679Sbostic /*                                                                 */
1520*45679Sbostic /*    This routine copies ACP I/O requests into the ACP comm regs  */
1521*45679Sbostic /*    and notifies the ACP.                                        */
1522*45679Sbostic /*                                                                 */
1523*45679Sbostic /*  Call:              start_chn(ds)                               */
1524*45679Sbostic /*  Argument:          ds:  pointer to device control block struct */
1525*45679Sbostic /*  Returns:           nothing                                     */
1526*45679Sbostic /*  Called by:         acpinta()                                   */
1527*45679Sbostic /*                     acp_iorq()                                  */
1528*45679Sbostic /*  Calls to:          none                                        */
1529*45679Sbostic /*                                                                 */
1530*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1531*45679Sbostic 
1532*45679Sbostic static void start_chn(ds)
1533*45679Sbostic struct acp_softc *ds;
1534*45679Sbostic   {
1535*45679Sbostic     register struct hdx_chan *hc = ds->acp_sioq.sq_head;
1536*45679Sbostic     register struct acpregs *addr =
1537*45679Sbostic     	(struct acpregs *)acpinfo[ds->acp_if.if_unit]->ui_addr;
1538*45679Sbostic 
1539*45679Sbostic     /*
1540*45679Sbostic      * Set up comm regs.
1541*45679Sbostic      */
1542*45679Sbostic 
1543*45679Sbostic #ifdef ACPDEBUG
1544*45679Sbostic if (acp_debug > 7)
1545*45679Sbostic   {
1546*45679Sbostic       printf("acp: start_chn()\n");
1547*45679Sbostic   }
1548*45679Sbostic #endif ACPDEBUG
1549*45679Sbostic 
1550*45679Sbostic     addr->req_chan = hc->hc_chan >> 1;
1551*45679Sbostic     addr->req_adx = hc->hc_adx;
1552*45679Sbostic     addr->req_addr = hc->hc_addr;
1553*45679Sbostic     addr->req_cnt = hc->hc_cnt;
1554*45679Sbostic     addr->req_fcn = hc->hc_func;
1555*45679Sbostic     addr->req_sbf = hc->hc_sbfc;
1556*45679Sbostic     if (hc->hc_chan & 1)
1557*45679Sbostic 	addr->req_flags = FLAGS_RDY | FLAGS_DIR;
1558*45679Sbostic     else
1559*45679Sbostic 	addr->req_flags = FLAGS_RDY;
1560*45679Sbostic 
1561*45679Sbostic     addr->csr |= CSR_INTRA;
1562*45679Sbostic   }
1563*45679Sbostic 
1564*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1565*45679Sbostic /*%%                      ACP_DATA()                             %%*/
1566*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1567*45679Sbostic /*                                                                 */
1568*45679Sbostic /*  Purpose:                                                       */
1569*45679Sbostic /*                                                                 */
1570*45679Sbostic /*    This routine is called when a data channel I/O completes.    */
1571*45679Sbostic /*    If the completion was for a write, an attempt is made to     */
1572*45679Sbostic /*    start output on the next packet waiting for output on that   */
1573*45679Sbostic /*    LCN.  If the completion was for a read, the received packet  */
1574*45679Sbostic /*    is sent to the IP input queue (if no error) and another read */
1575*45679Sbostic /*    is started on the LCN.                                       */
1576*45679Sbostic /*                                                                 */
1577*45679Sbostic /*  Call:              acp_data(ds, hc, cc, rcnt)                  */
1578*45679Sbostic /*  Arguments:         ds:  pointer to device control block struct */
1579*45679Sbostic /*                     hc:  pointer to half duplex channel control */
1580*45679Sbostic /*                               block                             */
1581*45679Sbostic /*                     cc:  Mailbox I/O completion status          */
1582*45679Sbostic /*                     rcnt: byte count                            */
1583*45679Sbostic /*  Returns:           nothing                                     */
1584*45679Sbostic /*  Called by:         acpinta()                                   */
1585*45679Sbostic /*  Calls to:          m_freem()                                   */
1586*45679Sbostic /*                     acp_start()                                 */
1587*45679Sbostic /*                     if_rubaget()                                */
1588*45679Sbostic /*                     IF_QFULL()                                  */
1589*45679Sbostic /*                     IF_DROP()                                   */
1590*45679Sbostic /*                     IF_ENQUEUE()                                */
1591*45679Sbostic /*                     schednetisr()                               */
1592*45679Sbostic /*                     acp_ioreq()                                 */
1593*45679Sbostic /*                                                                 */
1594*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1595*45679Sbostic 
1596*45679Sbostic static void acp_data(ds, hc, cc, rcnt)
1597*45679Sbostic register struct acp_softc *ds;
1598*45679Sbostic register struct hdx_chan *hc;
1599*45679Sbostic int cc, rcnt;
1600*45679Sbostic {
1601*45679Sbostic     register struct acp_cb *dc = &(ds->acp_cb[hc->hc_chan/2]);
1602*45679Sbostic     register struct ifqueue *inq = &ipintrq;
1603*45679Sbostic     register struct mbuf *m;
1604*45679Sbostic 
1605*45679Sbostic     if (hc->hc_chan & 0x01)		/* was it read or write? */
1606*45679Sbostic       {					/*   write, fire up next output */
1607*45679Sbostic     	ds->acp_if.if_opackets++;
1608*45679Sbostic 	if (dc->dc_ifuba.ifu_xtofree)
1609*45679Sbostic 	  {
1610*45679Sbostic 	    m_freem(dc->dc_ifuba.ifu_xtofree);
1611*45679Sbostic 	    dc->dc_ifuba.ifu_xtofree = 0;
1612*45679Sbostic 	  }
1613*45679Sbostic     	dc->dc_flags &= ~DC_OBUSY;
1614*45679Sbostic     	acp_start(ds, dc);
1615*45679Sbostic       }
1616*45679Sbostic     else				/*   read, process rcvd packet */
1617*45679Sbostic       {
1618*45679Sbostic 
1619*45679Sbostic #ifdef ACPDEBUG
1620*45679Sbostic if (acp_debug > 6)
1621*45679Sbostic   {
1622*45679Sbostic printf("acp: data read completed, cc = %d, cnt = %d\n", cc, rcnt);
1623*45679Sbostic prt_bytes((u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr), (rcnt < 20 ? rcnt:20));
1624*45679Sbostic   }
1625*45679Sbostic #endif ACPDEBUG
1626*45679Sbostic 
1627*45679Sbostic     	if (cc == ACPIOCOK)
1628*45679Sbostic     	  {				 /* Queue good packet for input */
1629*45679Sbostic     	    ds->acp_if.if_ipackets++;
1630*45679Sbostic 	    if (rcnt > ds->acp_maxin)
1631*45679Sbostic 	      {
1632*45679Sbostic 
1633*45679Sbostic #ifdef ACPDEBUG
1634*45679Sbostic if (acp_debug > 4)
1635*45679Sbostic   {
1636*45679Sbostic     printf("acp: %d byte msg received.\n", rcnt);
1637*45679Sbostic   }
1638*45679Sbostic #endif ACPDEBUG
1639*45679Sbostic 
1640*45679Sbostic 		ds->acp_maxin = rcnt;
1641*45679Sbostic 	      }
1642*45679Sbostic 				/* call if_rubaget() to pull read data  */
1643*45679Sbostic 				/*  off the interface, the args are the */
1644*45679Sbostic 				/*  ifuba struct, the length of data,   */
1645*45679Sbostic 				/*  and the 0 indicates that no trailer */
1646*45679Sbostic 				/*  protocol is used                    */
1647*45679Sbostic     	    m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &(ds->acp_if));
1648*45679Sbostic     	    if (m)
1649*45679Sbostic     	      {
1650*45679Sbostic     		if (IF_QFULL(inq))
1651*45679Sbostic     		  {
1652*45679Sbostic     		    IF_DROP(inq);
1653*45679Sbostic     		    m_freem(m);
1654*45679Sbostic     		  }
1655*45679Sbostic     		else
1656*45679Sbostic     		  {
1657*45679Sbostic     		    IF_ENQUEUE(inq, m);
1658*45679Sbostic     		    schednetisr(NETISR_IP);
1659*45679Sbostic     		  }
1660*45679Sbostic     	      }
1661*45679Sbostic     	  }
1662*45679Sbostic 
1663*45679Sbostic     	/* hang a new data read */
1664*45679Sbostic 
1665*45679Sbostic     	acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
1666*45679Sbostic 
1667*45679Sbostic       }
1668*45679Sbostic   }
1669*45679Sbostic 
1670*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1671*45679Sbostic /*%%                      ACP_RESPONSE()                         %%*/
1672*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1673*45679Sbostic /*                                                                 */
1674*45679Sbostic /*  Purpose:                                                       */
1675*45679Sbostic /*                                                                 */
1676*45679Sbostic /*   This routine sends a Control Interface Message (CIM) response */
1677*45679Sbostic /*   to the front end to indicate that a CIM command from the      */
1678*45679Sbostic /*   front end was successfully received.  Presently there are two */
1679*45679Sbostic /*   types of CIM responses sent to the front end:  frame level    */
1680*45679Sbostic /*   up, and frame level down.  Future applications may send a     */
1681*45679Sbostic /*   CIM response to DCP CIM commands.  The basic philosophy with  */
1682*45679Sbostic /*   CIMs is that there is always a paired command/response which  */
1683*45679Sbostic /*   is exchanged between the host and the front end.              */
1684*45679Sbostic /*   Currently, the front end does not process the responses from  */
1685*45679Sbostic /*   the host, they are merely discarded.  The one thing left to   */
1686*45679Sbostic /*   do in the case that the front end does ever look at these     */
1687*45679Sbostic /*   responses is to use the same CID (Command ID field, bytes 5   */
1688*45679Sbostic /*   to 8 of the CIM header) that was present in the command.      */
1689*45679Sbostic /*                                                                 */
1690*45679Sbostic /*  Call:          acp_response(ds, response)                      */
1691*45679Sbostic /*  Argument:      ds:  pointer to ACP device control structure    */
1692*45679Sbostic /*                 response:  response for CIM command field       */
1693*45679Sbostic /*                   the response value = command value + 1        */
1694*45679Sbostic /*  Returns:       nothing                                         */
1695*45679Sbostic /*  Called by:     supr_msg()                                      */
1696*45679Sbostic /*  Calls to:          MGET()                                      */
1697*45679Sbostic /*                     printf()                                    */
1698*45679Sbostic /*                     mtod()                                      */
1699*45679Sbostic /*                     bcopy()                                     */
1700*45679Sbostic /*                     sizeof()                                    */
1701*45679Sbostic /*                     IF_ENQUEUE()                                */
1702*45679Sbostic /*                     acp_start()                                 */
1703*45679Sbostic /*                                                                 */
1704*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1705*45679Sbostic 
1706*45679Sbostic static void acp_response(ds, response)
1707*45679Sbostic struct acp_softc *ds;
1708*45679Sbostic u_char response;
1709*45679Sbostic   {
1710*45679Sbostic     struct mbuf *m;
1711*45679Sbostic     u_char *bp;
1712*45679Sbostic 
1713*45679Sbostic     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get init buffer */
1714*45679Sbostic     if (m == 0)
1715*45679Sbostic       {
1716*45679Sbostic     	printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
1717*45679Sbostic     	return;
1718*45679Sbostic       }
1719*45679Sbostic 			/* put response in CIM cmd field */
1720*45679Sbostic 
1721*45679Sbostic     response_msg[CMD_OFFSET] = response;
1722*45679Sbostic 
1723*45679Sbostic     bp = mtod(m, u_char *);		/* point to data section of mbuf */
1724*45679Sbostic 
1725*45679Sbostic     bcopy(response_msg, bp, sizeof(response_msg));  /* put msg in mbuf */
1726*45679Sbostic 
1727*45679Sbostic #ifdef ACPDEBUG
1728*45679Sbostic if (acp_debug > 6)
1729*45679Sbostic   {
1730*45679Sbostic printf("acp_response():  ");
1731*45679Sbostic prt_bytes(bp, sizeof(response_msg));   /* print messge  */
1732*45679Sbostic printf("\n");
1733*45679Sbostic   }
1734*45679Sbostic #endif ACPDEBUG
1735*45679Sbostic 
1736*45679Sbostic     m->m_len = sizeof(response_msg);		/* set msg length */
1737*45679Sbostic 
1738*45679Sbostic     IF_ENQUEUE(&(ds->acp_cb[ACP_SUPR].dc_oq), m);	/* output queue   */
1739*45679Sbostic 
1740*45679Sbostic     acp_start(ds, &(ds->acp_cb[ACP_SUPR]));	/* start ouput of data  */
1741*45679Sbostic   }
1742*45679Sbostic 
1743*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1744*45679Sbostic /*%%                      ACP_SUPR()                             %%*/
1745*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1746*45679Sbostic /*                                                                 */
1747*45679Sbostic /*  Purpose:                                                       */
1748*45679Sbostic /*                                                                 */
1749*45679Sbostic /*    This routine is called when a supervisor I/O completes.      */
1750*45679Sbostic /*    If the completion was for a write, an attempt is made to     */
1751*45679Sbostic /*    start output on the next supervisor command waiting for      */
1752*45679Sbostic /*    output.  If the completion was for a read, the received      */
1753*45679Sbostic /*    supervisor message is processed and another read is started. */
1754*45679Sbostic /*                                                                 */
1755*45679Sbostic /*  Call:              acp_supr(ds, hc, cc, rcnt, channel)         */
1756*45679Sbostic /*  Argument:          ds:   pointer to dev control block struct   */
1757*45679Sbostic /*                     hc:   pointer to the Half Duplex cntrl      */
1758*45679Sbostic /*                                 block structure                 */
1759*45679Sbostic /*                     cc:   Mailbox I/O completion status         */
1760*45679Sbostic /*                     rcnt:  byte count, length of data           */
1761*45679Sbostic /*                     channel:  indicates ACP_ALLOC or ACP_SUPR   */
1762*45679Sbostic /*  Returns:           nothing                                     */
1763*45679Sbostic /*  Called by:         acpinta()                                   */
1764*45679Sbostic /*  Calls to:          m_freem()                                   */
1765*45679Sbostic /*                     acp_start()                                 */
1766*45679Sbostic /*                     supr_msg()                                  */
1767*45679Sbostic /*                     acp_ioreq()                                 */
1768*45679Sbostic /*                                                                 */
1769*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1770*45679Sbostic 
1771*45679Sbostic static void acp_supr(ds, hc, cc, rcnt, chan)
1772*45679Sbostic register struct acp_softc *ds;
1773*45679Sbostic register struct hdx_chan *hc;
1774*45679Sbostic int cc, rcnt, chan;
1775*45679Sbostic   {
1776*45679Sbostic     register struct acp_cb *dc = &(ds->acp_cb[chan]);
1777*45679Sbostic     register u_char *p;
1778*45679Sbostic 
1779*45679Sbostic     /* was it read or write? */
1780*45679Sbostic 
1781*45679Sbostic     if (hc->hc_chan & 0x01)
1782*45679Sbostic       {
1783*45679Sbostic 	if (dc->dc_ifuba.ifu_xtofree)
1784*45679Sbostic 	  {
1785*45679Sbostic 	    m_freem(dc->dc_ifuba.ifu_xtofree);
1786*45679Sbostic 	    dc->dc_ifuba.ifu_xtofree = 0;
1787*45679Sbostic 	  }
1788*45679Sbostic     	dc->dc_flags &= ~DC_OBUSY;
1789*45679Sbostic     	acp_start(ds, dc);
1790*45679Sbostic       }
1791*45679Sbostic     else
1792*45679Sbostic       {
1793*45679Sbostic 
1794*45679Sbostic #ifdef ACPDEBUG
1795*45679Sbostic if (acp_debug > 3)
1796*45679Sbostic   {
1797*45679Sbostic printf("acp: acp_supr(), read completed, cc = %d, cnt = %d\n", cc, rcnt);
1798*45679Sbostic prt_bytes((u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr), rcnt);
1799*45679Sbostic printf("\n");
1800*45679Sbostic   }
1801*45679Sbostic #endif ACPDEBUG
1802*45679Sbostic 
1803*45679Sbostic     	if (cc == ACPIOCOK)
1804*45679Sbostic     	  {
1805*45679Sbostic     	    p = (u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr);
1806*45679Sbostic 
1807*45679Sbostic     	    /* process supervisor message */
1808*45679Sbostic     	    supr_msg(ds, p);
1809*45679Sbostic     	  }
1810*45679Sbostic     	/* hang a new supr read */
1811*45679Sbostic     	acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
1812*45679Sbostic       }
1813*45679Sbostic   }
1814*45679Sbostic 
1815*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1816*45679Sbostic /*%%                      SUPR_MSG()                             %%*/
1817*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1818*45679Sbostic /*                                                                 */
1819*45679Sbostic /*  Purpose:                                                       */
1820*45679Sbostic /*                                                                 */
1821*45679Sbostic /*       This routine processes received supervisor messages.      */
1822*45679Sbostic /*       Depending on the message type, the appropriate action is  */
1823*45679Sbostic /*       taken.  Note that the RSF field is checked for responses. */
1824*45679Sbostic /*       The RSF field is 4 bytes long, but ony that least         */
1825*45679Sbostic /*       significant byte is used.                                 */
1826*45679Sbostic /*                                                                 */
1827*45679Sbostic /*  Call:              supr_msg(ds, p)                             */
1828*45679Sbostic /*  Arguments:         ds:  pointer to dev control block struct    */
1829*45679Sbostic /*                     p:   pointer to a character array           */
1830*45679Sbostic /*                              containing the supervisor message  */
1831*45679Sbostic /*  Returns:           nothing                                     */
1832*45679Sbostic /*  Called by:         acp_supr()                                  */
1833*45679Sbostic /*  Calls to:          printf()                                    */
1834*45679Sbostic /*                     IF_DEQUEUE()                                */
1835*45679Sbostic /*                     m_freem()                                   */
1836*45679Sbostic /*                     acp_response()                              */
1837*45679Sbostic /*                                                                 */
1838*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1839*45679Sbostic 
1840*45679Sbostic static void supr_msg(ds, p)
1841*45679Sbostic struct acp_softc *ds;
1842*45679Sbostic u_char p[];
1843*45679Sbostic   {
1844*45679Sbostic     register struct acp_cb *dc;
1845*45679Sbostic     register int lcn;
1846*45679Sbostic     register struct mbuf *m;
1847*45679Sbostic 
1848*45679Sbostic     switch (p[3])
1849*45679Sbostic       {
1850*45679Sbostic     case RSP_ALLOC:			/*  alloc response   */
1851*45679Sbostic         if (p[RSF_OFFSET])	/* check if RSF is 0 for success */
1852*45679Sbostic           {
1853*45679Sbostic             printf("acp%d:  attempt to allocate path failed ");
1854*45679Sbostic             printf("rsf field = %x\n", p[RSF_OFFSET]);
1855*45679Sbostic             return;
1856*45679Sbostic           }
1857*45679Sbostic         else
1858*45679Sbostic           {
1859*45679Sbostic             if (p[CID_OFFSET] >=  ACP_SUPR  &&  p[CID_OFFSET] <= ACP_DATA )
1860*45679Sbostic                 ds->acp_path |= p[CID_OFFSET];
1861*45679Sbostic             else
1862*45679Sbostic               {
1863*45679Sbostic                 printf("acp%d:  path allocation ",ds->acp_if.if_unit);
1864*45679Sbostic                 printf("response contains invalid DPN = %d\n", p[CID_OFFSET]);
1865*45679Sbostic               }
1866*45679Sbostic           }
1867*45679Sbostic         break;
1868*45679Sbostic 
1869*45679Sbostic     case RSP_DEALLOC:			/*  dealloc response */
1870*45679Sbostic         if (p[RSF_OFFSET])	/* check if RSF is 0 for success */
1871*45679Sbostic           {
1872*45679Sbostic             printf("acp%d:  attempt to deallocate path failed ");
1873*45679Sbostic             printf("rsf field = %x\n", p[RSF_OFFSET]);
1874*45679Sbostic             return;
1875*45679Sbostic           }
1876*45679Sbostic         break;
1877*45679Sbostic 
1878*45679Sbostic     case RSP_SSP:			/*  set sys parm rsp */
1879*45679Sbostic         if (p[RSF_OFFSET])	/* check if RSF is 0 for success */
1880*45679Sbostic           {
1881*45679Sbostic             printf("acp%d:  attempt to set HDLC system parameters failed\n");
1882*45679Sbostic             return;
1883*45679Sbostic           }
1884*45679Sbostic         break;
1885*45679Sbostic 
1886*45679Sbostic     case CMD_FLUP:			/*   frame level up  */
1887*45679Sbostic 
1888*45679Sbostic 	/* check that the data path was successfully allocated, we */
1889*45679Sbostic 	/* know that the control path was successfully allocated   */
1890*45679Sbostic 	/* otherwise the FLUP command would not have been issued   */
1891*45679Sbostic 
1892*45679Sbostic         if ((ds->acp_path & ACP_DATA) == 0)
1893*45679Sbostic           {
1894*45679Sbostic             printf("acp%d:  data path was not successfully allocated\n",
1895*45679Sbostic 			ds->acp_if.if_unit);
1896*45679Sbostic           }
1897*45679Sbostic         ds->acp_if.if_flags |= IFF_UP;
1898*45679Sbostic         printf("acp%d:  frame level up\n", ds->acp_if.if_unit);
1899*45679Sbostic         acp_response(ds, RSP_FLUP);	/* send response to front end */
1900*45679Sbostic         break;
1901*45679Sbostic 
1902*45679Sbostic     case CMD_FLDWN:			/* frame level down  */
1903*45679Sbostic         ds->acp_if.if_flags &= ~IFF_UP;
1904*45679Sbostic         dc = ds->acp_cb;
1905*45679Sbostic         for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++)	/* for all LCN's */
1906*45679Sbostic           {
1907*45679Sbostic             while (dc->dc_oq.ifq_len) /* drop pending data */
1908*45679Sbostic               {
1909*45679Sbostic  	        IF_DEQUEUE(&dc->dc_oq, m);
1910*45679Sbostic     	        m_freem(m);
1911*45679Sbostic               }
1912*45679Sbostic 	    dc++;
1913*45679Sbostic     	  }
1914*45679Sbostic         printf("acp%d:  frame level down\n", ds->acp_if.if_unit);
1915*45679Sbostic         acp_response(ds, RSP_FLDWN);	/* send response to front end */
1916*45679Sbostic     	break;
1917*45679Sbostic 
1918*45679Sbostic     default:
1919*45679Sbostic     	printf("acp%d: supervisor error, code=%x\n",
1920*45679Sbostic 	   ds->acp_if.if_unit, p[3]);
1921*45679Sbostic       }
1922*45679Sbostic   }
1923*45679Sbostic 
1924*45679Sbostic 
1925*45679Sbostic #ifdef ACPDEBUG
1926*45679Sbostic 
1927*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1928*45679Sbostic /*%%                            PRT_ADDR()                             %%*/
1929*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1930*45679Sbostic /*                                                                       */
1931*45679Sbostic /*  Purpose:                                                             */
1932*45679Sbostic /*                                                                       */
1933*45679Sbostic /*	This routine is used to print internet addresses in the		 */
1934*45679Sbostic /*	standard A.B.C.D format.  Note that this routine is for          */
1935*45679Sbostic /*	debugging purposes (ifdef ACPDEBUG).                             */
1936*45679Sbostic /*									 */
1937*45679Sbostic /*  Call:  		prt_addr(addr)                                   */
1938*45679Sbostic /*  Argument:      	addr:  internet address structure                */
1939*45679Sbostic /*  Returns:  		nothing                                          */
1940*45679Sbostic /*  Called by:  	acpoutput()                                      */
1941*45679Sbostic /*  Calls to:   	printf()                                         */
1942*45679Sbostic /*									 */
1943*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1944*45679Sbostic 
1945*45679Sbostic static void prt_addr(addr)
1946*45679Sbostic struct in_addr addr;
1947*45679Sbostic   {
1948*45679Sbostic #ifndef FOURTWO
1949*45679Sbostic         union {
1950*45679Sbostic                 struct in_addr ip;
1951*45679Sbostic                 struct {                /* (assume Class A network number) */
1952*45679Sbostic                         u_char s_net;
1953*45679Sbostic                         u_char s_host;
1954*45679Sbostic                         u_char s_lh;
1955*45679Sbostic                         u_char s_impno;
1956*45679Sbostic                 } imp;
1957*45679Sbostic         } imp_addr;
1958*45679Sbostic         imp_addr.ip = addr;
1959*45679Sbostic     printf("%d.%d.%d.%d", imp_addr.imp.s_net, imp_addr.imp.s_host,
1960*45679Sbostic                 imp_addr.imp.s_lh, imp_addr.imp.s_impno);
1961*45679Sbostic #else
1962*45679Sbostic     printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
1963*45679Sbostic #endif
1964*45679Sbostic   }
1965*45679Sbostic 
1966*45679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1967*45679Sbostic /*%%                            PRT_BYTES()                            %%*/
1968*45679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1969*45679Sbostic /*                                                                       */
1970*45679Sbostic /*  Purpose:                                                             */
1971*45679Sbostic /*                                                                       */
1972*45679Sbostic /*	This routine is used to print a string of bytes in hex.		 */
1973*45679Sbostic /*	Note that this routine is for debugging purposes (ifdef          */
1974*45679Sbostic /*	ACPDEBUG).                                                       */
1975*45679Sbostic /*									 */
1976*45679Sbostic /*  Call:  		prt_bytes(bp, cnt)                               */
1977*45679Sbostic /*  Argument:      	bp:  pointer to the string                       */
1978*45679Sbostic /*                 	cnt: number of bytes                             */
1979*45679Sbostic /*  Returns:  		nothing                                          */
1980*45679Sbostic /*  Called by:  	acp_data()                                       */
1981*45679Sbostic /*              	acp_supr()                                       */
1982*45679Sbostic /*              	supr_msg()                                       */
1983*45679Sbostic /*  Calls to:   	printf()                                         */
1984*45679Sbostic /*									 */
1985*45679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1986*45679Sbostic 
1987*45679Sbostic static void prt_bytes(bp, cnt)
1988*45679Sbostic u_char *bp;
1989*45679Sbostic int cnt;
1990*45679Sbostic   {
1991*45679Sbostic     while(cnt--)
1992*45679Sbostic       {
1993*45679Sbostic 	printf(" %x", *bp++ & 0xff);
1994*45679Sbostic       }
1995*45679Sbostic   }
1996*45679Sbostic 
1997*45679Sbostic #endif ACPDEBUG
1998*45679Sbostic 
1999*45679Sbostic #endif NACP
2000