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