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