xref: /csrg-svn/sys/vax/if/if_acp.c (revision 45801)
145682Sbostic /*-
2*45801Sbostic  *	@(#)if_acp.c	7.3 (Berkeley) 12/16/90
345682Sbostic  */
445679Sbostic 
545679Sbostic /*************************************************************************/
645679Sbostic /*                                                                       */
745679Sbostic /*                                                                       */
845679Sbostic /*       ________________________________________________________        */
945679Sbostic /*      /                                                        \       */
1045679Sbostic /*     |          AAA          CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |      */
1145679Sbostic /*     |         AAAAA        CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |      */
1245679Sbostic /*     |        AAAAAAA       CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |      */
1345679Sbostic /*     |       AAAA AAAA      CCCC              CCCC              |      */
1445679Sbostic /*     |      AAAA   AAAA     CCCC              CCCC              |      */
1545679Sbostic /*     |     AAAA     AAAA    CCCC              CCCC              |      */
1645679Sbostic /*     |    AAAA       AAAA   CCCC              CCCC              |      */
1745679Sbostic /*     |   AAAA  AAAAAAAAAAA  CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |      */
1845679Sbostic /*     |  AAAA    AAAAAAAAAAA CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |      */
1945679Sbostic /*     | AAAA      AAAAAAAAA   CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |      */
2045679Sbostic /*      \________________________________________________________/       */
2145679Sbostic /*                                                                       */
2245679Sbostic /*  	Copyright (c) 1985 by Advanced Computer Communications           */
2345679Sbostic /*  	720 Santa Barbara Street, Santa Barbara, California  93101       */
2445679Sbostic /*  	(805) 963-9431                                                   */
2545679Sbostic /*                                                                       */
2645679Sbostic /*                                                                       */
2745679Sbostic /*  File:		if_acp.c                                         */
2845679Sbostic /*                                                                       */
2945679Sbostic /*  Author:		Arthur Berggreen                                 */
3045679Sbostic /*                                                                       */
3145679Sbostic /*  Project:		ACP6100 (UPB with HDLC firmware)                 */
3245679Sbostic /*                                                                       */
3345679Sbostic /*  Function:		4.2BSD UNIX Network Interface Driver for ACP6100 */
3445679Sbostic /*                                                                       */
3545679Sbostic /*  Components:		if_acp.c, if_acpreg.h, if_acpvar.h               */
3645679Sbostic /*                                                                       */
3745679Sbostic /*  Revision History:                                                    */
3845679Sbostic /*                                                                       */
3945679Sbostic /*    16-AUG-1985  Clare Russ:  add fileheader and comments              */
4045679Sbostic /*    24-SEP-1985  Clare Russ:  modify for socket ioctl user interface   */
4145679Sbostic /*    06-NOV-1985  Clare Russ:  modify for socket ioctl under TWG        */
4245679Sbostic /*    11-NOV-1985  Clare Russ:  Add a call to acpreset() in acpioctl()   */
4345679Sbostic /*         before processing socket ioctl to clear COMREGs.  In the      */
4445679Sbostic /*         acpinit() routine, avoid redundant allocation of UMRs by      */
4545679Sbostic /*         doing so only if the front end is not RUNNING.                */
4645679Sbostic /*    14-NOV-1985  Clare Russ:  Trace if_ubainit failure:  happens with  */
4745679Sbostic /*         TWG, not 4.2BSD.                                              */
4845679Sbostic /*    21-NOV-1985  Clare Russ:  Modify for compliance with the new       */
4945679Sbostic /*         Control Interface (CIF) and Access Path Allocation Protocol   */
5045679Sbostic /*         (APAP).  The CIF requires that Control Interface Messages     */
5145679Sbostic /*         (CIMs) are exchanged between the host and front end in        */
5245679Sbostic /*         command/response pairs.  The APAP requires that the control   */
5345679Sbostic /*         and data paths be established (via exchange of CIMs between   */
5445679Sbostic /*         the host and the front end) prior to use.                     */
5545679Sbostic /*    26-NOV-1985  Clare Russ:  Add ability to bring down line in        */
5645679Sbostic /*         response to 'acpconfig' command.                              */
5745679Sbostic /*    27-NOV-1985  Clare Russ:  Add ability to specify DTE or DCE mode   */
5845679Sbostic /*         in response to 'acpconfig' command.                           */
5945679Sbostic /*    02-DEC-1985  Clare Russ:  Add ability to set baud rate (external   */
6045679Sbostic /*         clock) or set internal clock.                                 */
6145679Sbostic /*    14-JAN-1986  Clare Russ:  Add acpinit call to acpioctl under       */
6245679Sbostic /*         SIOCSIFADDR processing                                        */
6345679Sbostic /*    21-JAN-1986  Clare Russ:  Flush pending I/O in acpreset, free the  */
6445679Sbostic /*         mbufs                                                         */
6545679Sbostic /*    30-MAY-1986  Clare Russ:  Update MPCP host request subfunction     */
6645679Sbostic /*         values, fix baud rate values in baud_rate[], change default   */
6745679Sbostic /*         clock source from internal to external (in ssp_msg[])         */
6845679Sbostic /*    24-JUL-1986  Clare Russ:  In supr_msg() print out RSF field when   */
6945679Sbostic /*         path allocation or deallocation fails                         */
7045679Sbostic /*    23-FEB-1987  Jeff Berkowitz: port to 4.3BSD by adding #ifdefs for  */
7145679Sbostic /*	   new interface address formats, trapping 0 length mbufs, etc.  */
7245679Sbostic /*    08-JAN-1988  Brad Engstrom:  port to ULTRIX 2.0 by using the       */
7345679Sbostic /*	   UBAUVII (ultrix 2.0) and MVAX (microvax) defines to handle    */
7445679Sbostic /*         special cases.  These cases are:                              */
7545679Sbostic /*         1) not declaring br, cvec as value-result in the probe routine*/
7645679Sbostic /*         2) using 0x17 as the ipl for a microvax                       */
7745679Sbostic /*         3) in all other cases the ULTRIX drivers behaves like a 4.3   */
7845679Sbostic /*            driver.                                                    */
7945679Sbostic /*                                                                       */
8045679Sbostic /*  Usage Notes:                                                         */
8145679Sbostic /*                                                                       */
8245679Sbostic /*    device acp0 at uba0 csr 016700 flags 0 vector acpinta acpintb      */
8345679Sbostic /*                                                                       */
8445679Sbostic /*         The 'flags' value is nonzero in the configuration file        */
8545679Sbostic /*         for TWG, and may be left as zero in the configuration         */
8645679Sbostic /*         file for UNIX 4.2 BSD.                                        */
8745679Sbostic /*                                                                       */
8845679Sbostic /*  Application Notes:	                                                 */
8945679Sbostic /*                                                                       */
9045679Sbostic /*    Refer to the Installation Instructions and the UNIX Programmer's   */
9145679Sbostic /*    Manual page which are on the driver distribution medium.           */
9245679Sbostic /*                                                                       */
9345679Sbostic /*                                                                       */
9445679Sbostic /*************************************************************************/
9545679Sbostic 
9645679Sbostic 
9745679Sbostic /* #define ACPDEBUG 1	/* define for debug printf statements */
9845679Sbostic 
9945679Sbostic #ifdef ACPDEBUG
10045679Sbostic int acp_debug = 0;	/* acp_debug is 1-8 for increasing verbosity */
10145679Sbostic #endif ACPDEBUG
10245679Sbostic 
10345679Sbostic 
10445679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
10545679Sbostic /*%%                                                                   %%*/
10645679Sbostic /*%%                          INCLUDE FILES                            %%*/
10745679Sbostic /*%%                                                                   %%*/
10845679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
10945679Sbostic 
11045679Sbostic /* The number of ACP 6100s in the system is defined in the configuration */
11145679Sbostic /* file in /sys/conf.  When 'config' is run, the file acp.h is created   */
11245679Sbostic /* with the definition of NACP, the number of ACP 6100s in the system.   */
11345679Sbostic 
11445679Sbostic #include "acp.h"
11545679Sbostic #if NACP > 0
116*45801Sbostic #include "../include/pte.h"
11745679Sbostic 
118*45801Sbostic #include "sys/param.h"
119*45801Sbostic #include "sys/systm.h"
120*45801Sbostic #include "sys/mbuf.h"
121*45801Sbostic #include "sys/buf.h"
122*45801Sbostic #include "sys/protosw.h"
123*45801Sbostic #include "sys/socket.h"
124*45801Sbostic #include "sys/vmmac.h"
125*45801Sbostic #include "sys/errno.h"
126*45801Sbostic #include "sys/time.h"
127*45801Sbostic #include "sys/kernel.h"
128*45801Sbostic #include "sys/ioctl.h"
12945679Sbostic 
130*45801Sbostic #include "net/if.h"
131*45801Sbostic #include "net/netisr.h"
132*45801Sbostic #include "net/route.h"
133*45801Sbostic #include "netinet/in.h"
134*45801Sbostic #include "netinet/in_systm.h"
13545679Sbostic #ifndef FOURTWO
136*45801Sbostic # include "netinet/in_var.h"
13745679Sbostic #endif
138*45801Sbostic #include "netinet/ip.h"
139*45801Sbostic #include "netinet/ip_var.h"
14045679Sbostic 
141*45801Sbostic #include "../include/cpu.h"
142*45801Sbostic #include "../include/mtpr.h"
143*45801Sbostic #include "../if/if_acpreg.h"
144*45801Sbostic #include "../if/if_acpvar.h"
145*45801Sbostic #include "../if/if_uba.h"
146*45801Sbostic #include "../uba/ubareg.h"
147*45801Sbostic #include "../uba/ubavar.h"
14845679Sbostic 
14945679Sbostic 
15045679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
15145679Sbostic /*%%                                                                   %%*/
15245679Sbostic /*%%                        GLOBAL FUNCTIONS                           %%*/
15345679Sbostic /*%%                                                                   %%*/
15445679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
15545679Sbostic 
15645679Sbostic int acpprobe();
15745679Sbostic int acpattach();
15845679Sbostic int acpreset();
15945679Sbostic int acpinit();
16045679Sbostic int acpoutput();
16145679Sbostic int acptimer();		/* currently no timer routine exists   */
16245679Sbostic int acpioctl();
16345679Sbostic int acpinta();
16445679Sbostic int acpintb();
16545679Sbostic int acpstart();
16645679Sbostic 
16745679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
16845679Sbostic /*%%                                                                   %%*/
16945679Sbostic /*%%                         LOCAL FUNCTIONS                           %%*/
17045679Sbostic /*%%                                                                   %%*/
17145679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
17245679Sbostic 
17345679Sbostic static void acp_alloc();	/* allocate control and data paths       */
17445679Sbostic static void acp_init();		/* send Set System Parameters Message    */
17545679Sbostic static void acp_iorq();
17645679Sbostic static void start_chn();
17745679Sbostic static void acp_data();
17845679Sbostic static void acp_response();	/* send CIM response to the front end    */
17945679Sbostic static void acp_supr();
18045679Sbostic static void supr_msg();
18145679Sbostic static void send_supr();
18245679Sbostic 
18345679Sbostic #ifdef ACPDEBUG
18445679Sbostic static void prt_addr();
18545679Sbostic static void prt_bytes();
18645679Sbostic #endif ACPDEBUG
18745679Sbostic 
18845679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
18945679Sbostic /*%%                                                                   %%*/
19045679Sbostic /*%%                         LOCAL VARIABLES                           %%*/
19145679Sbostic /*%%                                                                   %%*/
19245679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
19345679Sbostic 
19445679Sbostic struct	uba_device *acpinfo[NACP];	/* ptrs to device info           */
19545679Sbostic u_short	acpstd[] = { 0767000, 0 };	/* standard UNIBUS CSR addresses */
19645679Sbostic struct	uba_driver acpdriver =		/* device driver info            */
19745679Sbostic   {
19845679Sbostic     acpprobe,				/* device probe routine */
19945679Sbostic     0,					/* slave probe routine */
20045679Sbostic     acpattach,				/* device attach routine */
20145679Sbostic     0,					/* "dmago" routine */
20245679Sbostic     acpstd,				/* device address */
20345679Sbostic     "acp",				/* device name */
20445679Sbostic     acpinfo				/* ptr to device info ptrs */
20545679Sbostic   };
20645679Sbostic 
20745679Sbostic /* The alloc_msg array contains the Command Interface Message (CIM)    */
20845679Sbostic /* for path allocation.  There are 12 bytes of header followed by 6    */
20945679Sbostic /* bytes of command information                                        */
21045679Sbostic 
21145679Sbostic static u_char alloc_msg[] =
21245679Sbostic   {
21345679Sbostic     0x00,				/* reserved, must be zero      */
21445679Sbostic     FAC_ALLOC,				/* front end ALLOC facility    */
21545679Sbostic     0x00,				/* reserved, must be zero      */
21645679Sbostic     CMD_ALLOC,				/* allocate path command       */
21745679Sbostic     0x0f, 0x0a, 0x0c, 0x0e,		/* Command ID (CID)            */
21845679Sbostic     0x00, 0x00, 0x00, 0x00,		/* Response/Status Field (RSF) */
21945679Sbostic     0x00, ACP_SUPR,			/* Data Path Number (DPN)      */
22045679Sbostic     0x00, FAC_HDLC,			/* front end HDLC facility     */
22145679Sbostic     0x00, TYPE_CNTL			/* type of path:  control      */
22245679Sbostic   };
22345679Sbostic 
22445679Sbostic 
22545679Sbostic /* The dealloc_msg array contains the Command Interface Message (CIM)  */
22645679Sbostic /* for path deallocation.  There are 12 bytes of header followed by 2  */
22745679Sbostic /* bytes of command information                                        */
22845679Sbostic 
22945679Sbostic static u_char dealloc_msg[] =
23045679Sbostic   {
23145679Sbostic     0x00,				/* reserved, must be zero      */
23245679Sbostic     FAC_ALLOC,				/* front end ALLOC facility    */
23345679Sbostic     0x00,				/* reserved, must be zero      */
23445679Sbostic     CMD_DEALLOC,			/* allocate path command       */
23545679Sbostic     0x0c, 0x0a, 0x0f, 0x0e,		/* Command ID (CID)            */
23645679Sbostic     0x00, 0x00, 0x00, 0x00,		/* Response/Status Field (RSF) */
23745679Sbostic     0x00, ACP_SUPR,			/* Data Path Number (DPN)      */
23845679Sbostic   };
23945679Sbostic 
24045679Sbostic 
24145679Sbostic /* Table of baud rate values and the associated parameter for the Set  */
24245679Sbostic /* System Parameters message, ssp_msg.  The second byte is nonzero for */
24345679Sbostic /* valid baud rate divisors.                                           */
24445679Sbostic 
24545679Sbostic struct	baud	{
24645679Sbostic 	char	b_value;
24745679Sbostic 	u_char	parameter1;	/* first byte of baud rate setting  */
24845679Sbostic 	u_char	parameter2;	/* second byte of baud rate setting */
24945679Sbostic }	baud_rate[] =	{
25045679Sbostic 	{ 1,	0x00, 	0x02 },
25145679Sbostic 	{ 2,	0x00, 	0x03 },
25245679Sbostic 	{ 3,	0x00, 	0x04 },
25345679Sbostic 	{ 4,	0x00, 	0x08 },
25445679Sbostic 	{ 5,	0x00, 	0x10 },
25545679Sbostic 	{ 6,	0x00, 	0x28 },
25645679Sbostic 	{ 7,	0x00, 	0x3e },
25745679Sbostic 	{ 8,	0x00, 	0x47 },
25845679Sbostic 	{ 9,	0x00, 	0x85 },
25945679Sbostic 	{ 10,	0x00, 	0xd0 },
26045679Sbostic 	{ 11,	0x01, 	0xa1 },
26145679Sbostic 	{ 12,	0x03, 	0x41 },
26245679Sbostic 	{ 13,	0x06,	0x83 },
26345679Sbostic 	{ 14,	0x0d, 	0x05 },
26445679Sbostic 	{ 0,	0,	0 },
26545679Sbostic };
26645679Sbostic 
26745679Sbostic /* The ssp_msg array contains the Command Interface Message (CIM) for  */
26845679Sbostic /* Setting HDLC System Paramters.  There are 12 bytes of header        */
26945679Sbostic /* followed by the line number and parameter modification commands     */
27045679Sbostic /* (PMCs).  The driver sends this CIM to the front end when kicked by  */
27145679Sbostic /* the acpconfig program (via socket ioctl).  In future versions, the  */
27245679Sbostic /* CIM won't be here in the driver, it will be passed to the driver.   */
27345679Sbostic 
27445679Sbostic u_char ssp_msg[] =
27545679Sbostic   {
27645679Sbostic     0x00,				/* reserved, must be zero      */
27745679Sbostic     FAC_HDLC,				/* front end HDLC facility     */
27845679Sbostic     0x00,				/* reserved, must be zero      */
27945679Sbostic     CMD_SSP,				/* set HDCL system parameters  */
28045679Sbostic     0x0b, 0x0e, 0x0e, 0x0f,		/* Command ID (CID)            */
28145679Sbostic     0x00, 0x00, 0x00, 0x00,		/* Response/Status Field (RSF) */
28245679Sbostic     0x00, 0x00,				/* HDLC Line Number (0)        */
28345679Sbostic     LINK_DISABLE,			/* link disable                */
28445679Sbostic     LINK_LOOPBACK,			/* loopback mode               */
28545679Sbostic     LOOP_EXTERNAL,			/*   external loopback         */
28645679Sbostic     DCE_OR_DTE,				/* specify DTE or DCE mode     */
28745679Sbostic     DTE_MODE,				/*   DTE mode                  */
28845679Sbostic     BAUD_CNTL,				/* baud rate divisor           */
28945679Sbostic     0x00,				/*                             */
29045679Sbostic     0x03,				/*  3 = 1.333 Mb/sec           */
29145679Sbostic     IDLE_POLL,				/* idle poll selection         */
29245679Sbostic     0x01,				/*  1 = on                     */
29345679Sbostic     CLOCK_CNTL,				/* xmit clock selection        */
29445679Sbostic     0x00,				/*  0 = external source        */
29545679Sbostic     LINK_ENABLE				/* link enable                 */
29645679Sbostic   };
29745679Sbostic 
29845679Sbostic /* The response_msg array contains the Command Interface Message (CIM) */
29945679Sbostic /* response to be sent back to the front end in response to a CIM      */
30045679Sbostic /* command for Frame Level Status from the front end.   The front end  */
30145679Sbostic /* sends the Frame Level Status CIM command to the host when the frame */
30245679Sbostic /* level status changes from up to down or vice versa.  In keeping     */
30345679Sbostic /* with the philosophy with CIMs, they are always exchanged in command */
30445679Sbostic /* response pairs.                                                     */
30545679Sbostic 
30645679Sbostic static u_char response_msg[] =
30745679Sbostic   {
30845679Sbostic     0x00,				/* reserved, must be zero      */
30945679Sbostic     FAC_HDLC,				/* front end HDLC facility     */
31045679Sbostic     0x00,				/* reserved, must be zero      */
31145679Sbostic     RSP_FLUP,				/* Frame Level Status          */
31245679Sbostic     0x00, 0x00, 0x00, 0x00,		/* Command ID (CID)            */
31345679Sbostic     0x00, 0x00, 0x00, 0x00,		/* RSF is 0 for success        */
31445679Sbostic     0x00, 0x00				/* HDLC Line Number  (0)       */
31545679Sbostic   };
31645679Sbostic 
31745679Sbostic 
31845679Sbostic /***********************************************************************\
31945679Sbostic *									*
32045679Sbostic *	Information for each device unit is maintained in an array	*
32145679Sbostic *	of structures named acp_softc[].  The array is indexed by	*
32245679Sbostic *	unit number.  Each entry includes the network interface		*
32345679Sbostic *	structure (acp_if) used by the routing code to locate the	*
32445679Sbostic *	interface,  an array of Logical	Channel control blocks which	*
32545679Sbostic *	maintain information about each of the Logical Channels (LCNs)	*
32645679Sbostic *	through which communication with the ACP is maintained, a queue *
32745679Sbostic *	of I/O requests pending for the ACP, the UNIBUS interrupt	*
32845679Sbostic *	vector for the unit and misc flags.  The Logical Channel	*
32945679Sbostic *	Control blocks maintain information about the state of each	*
33045679Sbostic *	LCN, a queue of outbound data, Half Duplex Channel (HDX) blocks	*
33145679Sbostic *	used for queuing I/O requests to the ACP and an ifuba		*
33245679Sbostic *	structure which records the UNIBUS resources being held by	*
33345679Sbostic *	the LCN.							*
33445679Sbostic *									*
33545679Sbostic \***********************************************************************/
33645679Sbostic 
33745679Sbostic struct sioq		/* Start I/O queue head */
33845679Sbostic   {
33945679Sbostic     struct hdx_chan	*sq_head;	/* queue head */
34045679Sbostic     struct hdx_chan	*sq_tail;	/* queue tail */
34145679Sbostic   };
34245679Sbostic 
34345679Sbostic struct hdx_chan		/* HDX channel block */
34445679Sbostic   {
34545679Sbostic     struct hdx_chan	*hc_next;	/* link to next HDX channel */
34645679Sbostic     u_char		hc_chan;	/* HDX channel number */
34745679Sbostic     u_char		hc_adx;		/* address bits 17-16 */
34845679Sbostic     u_short		hc_addr;	/* address bits 15-00 */
34945679Sbostic     u_short		hc_cnt;		/* byte count */
35045679Sbostic     u_char		hc_func;	/* I/O function */
35145679Sbostic     u_char		hc_sbfc;	/* I/O subfunction */
35245679Sbostic   };
35345679Sbostic 
35445679Sbostic struct acp_cb		/* Logical Channel control block */
35545679Sbostic   {
35645679Sbostic     u_char		dc_lcn;		/* LCN number */
35745679Sbostic     struct ifqueue	dc_oq;		/* LCN output queue */
35845679Sbostic     struct hdx_chan	dc_rchan;	/* LCN read HDX channel */
35945679Sbostic     struct hdx_chan	dc_wchan;	/* LCN write HDX channel */
36045679Sbostic     struct ifuba	dc_ifuba;	/* UNIBUS resources */
36145679Sbostic     u_short		dc_flags;	/* misc flags */
36245679Sbostic   };
36345679Sbostic 
36445679Sbostic struct acp_softc	/* device control structure */
36545679Sbostic   {
36645679Sbostic     struct ifnet	acp_if;		/* network-visible interface   */
36745679Sbostic     struct acp_cb	acp_cb[NACPCH+1]; /* Logical Channel cntl blks */
36845679Sbostic     struct sioq		acp_sioq;	/* start I/O queue             */
36945679Sbostic     u_short		acp_vector;	/* UNIBUS interrupt vector     */
37045679Sbostic     u_short		acp_flags;	/* ACP operational flag        */
37145679Sbostic     u_char		acp_path;	/* path allocation flag        */
37245679Sbostic     u_short		acp_maxout;	/* maximum IP message sent     */
37345679Sbostic     u_short 		acp_maxin;	/* maximum IP message rcvd     */
37445679Sbostic #ifndef FOURTWO
37545679Sbostic     struct in_addr	acp_ipaddr;	/* local IP address */
37645679Sbostic #endif
37745679Sbostic   } acp_softc[NACP];
37845679Sbostic 
37945679Sbostic /* The acp_path flag indicates whether or not a path has been allocated */
38045679Sbostic /* and also whether or not to call acp_init to send an ssp_msg to the   */
38145679Sbostic /* front end:  acp_path = 1    indicates supervisory path is allocated  */
38245679Sbostic /*             acp_path = 2    indicates data path is allocated         */
38345679Sbostic /*             acp_path = 0x10 indicates acp_init should be called      */
38445679Sbostic /*                             to send CIM ssp_msg to the front end     */
38545679Sbostic 
38645679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38745679Sbostic /*%%                                                             %%*/
38845679Sbostic /*%%                   GLOBAL ROUTINES                           %%*/
38945679Sbostic /*%%                                                             %%*/
39045679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39145679Sbostic 
39245679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39345679Sbostic /*%%                      ACPPROBE()                             %%*/
39445679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39545679Sbostic /*                                                                 */
39645679Sbostic /* Purpose:                                                        */
39745679Sbostic /*                                                                 */
39845679Sbostic /*  This routine probes the device to obtain the UNIBUS interrupt  */
39945679Sbostic /*  vector.  Since the ACP is a soft vector device, we obtain an   */
40045679Sbostic /*  unused vector from the uba structure and return that.  The ACP */
40145679Sbostic /*  is given the vector and the board is reset.  In order to save  */
40245679Sbostic /*  the vector in the device info structure, we place it in a      */
40345679Sbostic /*  static temporary where the attach routine can find it and save */
40445679Sbostic /*  it in the device info structure.  This is necessary because    */
40545679Sbostic /*  probe only provides a pointer to the device and we have no     */
40645679Sbostic /*  idea which unit is being referenced.  This works in 4.2BSD     */
40745679Sbostic /*  because the attach routine is called immediately after a       */
40845679Sbostic /*  successful probe.                                              */
40945679Sbostic /*                                                                 */
41045679Sbostic /*  Call:          acpprobe(reg)                                   */
41145679Sbostic /*  Argument:      reg:  caddr_t address in virtual memory of the  */
41245679Sbostic /*                        control-status register                  */
41345679Sbostic /*  Returns:       length of register structure for ACP device     */
41445679Sbostic /*  Called by:     network software, part of autoconfiguration on  */
41545679Sbostic /*                 the VAX, the address of this routine is one of  */
41645679Sbostic /*                 the fields of the uba_driver structure          */
41745679Sbostic /*  Calls to:      nothing                                         */
41845679Sbostic /*                                                                 */
41945679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
42045679Sbostic 
42145679Sbostic static int savevec;			/* static variable for vector */
42245679Sbostic 
acpprobe(reg,ui)42345679Sbostic acpprobe(reg, ui)
42445679Sbostic caddr_t reg;
42545679Sbostic struct uba_device *ui;			/* TWG VAX/VMS ONLY! */
42645679Sbostic   {
42745679Sbostic #ifndef UBAUVII                         /* not for Ultrix 2.0 */
42845679Sbostic     register int br, cvec;		/* r11, r10 value-result */
42945679Sbostic #endif UBAUVII
43045679Sbostic     register struct acpregs *addr = (struct acpregs *)reg;
43145679Sbostic 
43245679Sbostic #ifdef lint
43345679Sbostic     br = 0; cvec = br; br = cvec;	/* these variables are value-result */
43445679Sbostic #endif
43545679Sbostic 
43645679Sbostic #ifdef VAXVMS
43745679Sbostic     cvec = savevec = ui->ui_flags & 0x1f8;	/* use flags from config file */
43845679Sbostic #else
43945679Sbostic     cvec = savevec = (uba_hd[numuba].uh_lastiv - 8) & ~7;
44045679Sbostic     uba_hd[numuba].uh_lastiv = cvec;
44145679Sbostic #endif VAXVMS
44245679Sbostic 
44345679Sbostic 					/* return a vector pair */
44445679Sbostic 					/*   aligned on QUADWORD boundary */
44545679Sbostic 
44645679Sbostic 					/* cvec is the interrupt vector   */
44745679Sbostic 					/*   address on the UNIBUS        */
44845679Sbostic 
44945679Sbostic 					/* br is the IPL of the device    */
45045679Sbostic 					/*   when it interrupts           */
45145679Sbostic 
45245679Sbostic #ifdef MVAX
45345679Sbostic     br = 0x17;				/* return bus level for a uVAX */
45445679Sbostic #else
45545679Sbostic     br = 0x15;				/* return bus level */
45645679Sbostic #endif MVAX
45745679Sbostic 
45845679Sbostic     addr->req_flags = 0;		/* clear handshake flags */
45945679Sbostic     addr->cmp_flags = 0;
46045679Sbostic     addr->xfr_flags = 0;
46145679Sbostic     addr->sys_stat = 0;
46245679Sbostic     addr->sys_vect = cvec >> 2;		/* pass vector to ACP */
46345679Sbostic     addr->csr = CSR_RESET;		/* reset the board */
46445679Sbostic     addr->csr |= CSR_IENB;		/* enable status intr */
46545679Sbostic 
46645679Sbostic     return (sizeof(struct acpregs));
46745679Sbostic   }
46845679Sbostic 
46945679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
47045679Sbostic /*%%                      ACPATTACH()                            %%*/
47145679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
47245679Sbostic /*                                                                 */
47345679Sbostic /*  Purpose:                                                       */
47445679Sbostic /*                                                                 */
47545679Sbostic /*  This routine attaches the device to the network software.  The */
47645679Sbostic /*  network interface structure is filled in.  The device will be  */
47745679Sbostic /*  initialized when the system is ready to accept packets.        */
47845679Sbostic /*                                                                 */
47945679Sbostic /*  Call:           acpattach(ui)                                  */
48045679Sbostic /*  Argument:       ui:  ptr to the uba_device data structure      */
48145679Sbostic /*  Returns:        nothing                                        */
48245679Sbostic /*  Called by:      network software, part of network system       */
48345679Sbostic /*                  configuration, identification to the network   */
48445679Sbostic /*                  software,  the address of this routine is one  */
48545679Sbostic /*                  of the fields of the uba_driver sturcture      */
48645679Sbostic /*  Calls to:       if_attach()                                    */
48745679Sbostic /*                                                                 */
48845679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
48945679Sbostic 
49045679Sbostic acpattach(ui)
49145679Sbostic struct uba_device *ui;
49245679Sbostic   {
49345679Sbostic     register struct acp_softc *ds = &acp_softc[ui->ui_unit];
49445679Sbostic 
49545679Sbostic     ds->acp_vector = savevec;		/* save vector from probe() */
49645679Sbostic     ds->acp_if.if_unit = ui->ui_unit;	/* set unit number */
49745679Sbostic     ds->acp_if.if_name = "acp";		/* set device name */
49845679Sbostic     ds->acp_if.if_mtu = ACPMTU;		/* set max msg size */
49945679Sbostic     ds->acp_if.if_init = acpinit;	/* set init routine addr */
50045679Sbostic     ds->acp_if.if_ioctl = acpioctl;	/* set ioctl routine addr */
50145679Sbostic     ds->acp_if.if_output = acpoutput;	/* set output routine addr */
50245679Sbostic     ds->acp_if.if_start = acpstart;	/* set start routine addr */
50345679Sbostic     ds->acp_if.if_reset = acpreset;	/* set reset routine addr */
50445679Sbostic     if_attach(&ds->acp_if);		/* attach new network device */
50545679Sbostic 					/*  add to list of "active"  */
50645679Sbostic 					/*  interfaces, the argument */
50745679Sbostic 					/*  passed locates the ifnet */
50845679Sbostic 					/*  data structure           */
50945679Sbostic   }
51045679Sbostic 
51145679Sbostic 
51245679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
51345679Sbostic /*%%                      ACPRESET()                             %%*/
51445679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
51545679Sbostic /*                                                                 */
51645679Sbostic /*  Purpose:                                                       */
51745679Sbostic /*                                                                 */
51845679Sbostic /*      Reset of interface after UNIBUS reset.  If interface is on */
51945679Sbostic /*      specified uba, reset its state.                            */
52045679Sbostic /*                                                                 */
52145679Sbostic /*  Call:              acpreset(unit, uban)                        */
52245679Sbostic /*  Arguments:         unit:   ACP device unit number              */
52345679Sbostic /*                     uban:   UNIBUS adapter number               */
52445679Sbostic /*  Returns:           nothing                                     */
52545679Sbostic /*  Called by:         network software, address of routine is     */
52645679Sbostic /*                     defined in acp_if network interface struct  */
52745679Sbostic /*  Calls to:          printf()                                    */
52845679Sbostic /*                     IF_DEQUEUE()                                */
52945679Sbostic /*                     m_freem()                                   */
53045679Sbostic /*                                                                 */
53145679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
53245679Sbostic 
acpreset(unit,uban)53345679Sbostic acpreset(unit, uban)
53445679Sbostic int unit, uban;
53545679Sbostic   {
53645679Sbostic     register struct uba_device *ui;	/* per "device" structure        */
53745679Sbostic     register struct acpregs *addr;	/* ACP device register struct    */
53845679Sbostic     register struct acp_cb *dc;
53945679Sbostic     register struct mbuf *m;
54045679Sbostic     register int lcn;
54145679Sbostic 
54245679Sbostic     if (unit >= NACP || (ui = acpinfo[unit]) == 0 || ui->ui_alive == 0 ||
54345679Sbostic       ui->ui_ubanum != uban)
54445679Sbostic 	return;
54545679Sbostic 
54645679Sbostic     printf("acp%d\n", unit);
54745679Sbostic 
54845679Sbostic     addr = (struct acpregs *)ui->ui_addr;  /* address of device in I/O space  */
54945679Sbostic 
55045679Sbostic     addr->req_flags = 0;		/* clear handshake flags, mailbox     */
55145679Sbostic 					/*  flags for I/O requests            */
55245679Sbostic     addr->cmp_flags = 0;		/* mailbox flags for I/O completion   */
55345679Sbostic     addr->xfr_flags = 0;		/* mailbox flags for I/O transfer     */
55445679Sbostic 					/*  requests                          */
55545679Sbostic     addr->sys_stat = 0;			/* mailbox flags for system status    */
55645679Sbostic     addr->sys_vect = acp_softc[unit].acp_vector >> 2;  /* pass base interrupt */
55745679Sbostic 					/*  vector to ACP                     */
55845679Sbostic     addr->csr = CSR_RESET;		/* reset the board                    */
55945679Sbostic     addr->csr |= CSR_IENB;		/* enable status intr                 */
56045679Sbostic     acp_softc[unit].acp_flags = 0;	/* clear ACP operational flag         */
56145679Sbostic     acp_softc[unit].acp_path = 0;	/* clear path allocation flag         */
56245679Sbostic 
56345679Sbostic     dc = acp_softc[unit].acp_cb;	/* flush any queued output data */
56445679Sbostic     for(lcn = 0; lcn <= NACPCH; lcn++)	/* for all LCN's ... */
56545679Sbostic     {
56645679Sbostic         while(dc->dc_oq.ifq_len)
56745679Sbostic             {
56845679Sbostic                 IF_DEQUEUE(&dc->dc_oq, m);
56945679Sbostic                 m_freem(m);
57045679Sbostic             }
57145679Sbostic         dc++;
57245679Sbostic     }
57345679Sbostic 
57445679Sbostic   }
57545679Sbostic 
57645679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
57745679Sbostic /*%%                      ACPINIT()                              %%*/
57845679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
57945679Sbostic /*                                                                 */
58045679Sbostic /*  Purpose:                                                       */
58145679Sbostic /*                                                                 */
58245679Sbostic /*    This routine initializes the interface for operation.  The   */
58345679Sbostic /*    device control blocks are initialized, UNIBUS resources are  */
58445679Sbostic /*    allocated and an initialization message is sent to the ACP.  */
58545679Sbostic /*                                                                 */
58645679Sbostic /*  Call:             acpinit(unit)                                */
58745679Sbostic /*  Argument:         unit:  ACP device unit number                */
58845679Sbostic /*  Returns:          nothing                                      */
58945679Sbostic /*  Called by:        network software, address of this routine is */
59045679Sbostic /*                    defined in acp_if network interface struct   */
59145679Sbostic /*                    acpioctl()                                   */
59245679Sbostic /*                    acpintb()                                    */
59345679Sbostic /*  Calls to:         in_netof() return the network number from    */
59445679Sbostic /*                               internet address                  */
59545679Sbostic /*                    if_ubainit()                                 */
59645679Sbostic /*                    btoc()                                       */
59745679Sbostic /*                    splimp()                                     */
59845679Sbostic /*                    acp_ioreq()                                  */
59945679Sbostic /*                    acp_alloc()                                  */
60045679Sbostic /*                    acp_init()                                   */
60145679Sbostic /*                    splx()                                       */
60245679Sbostic /*                    if_rtinit()                                  */
60345679Sbostic /*                                                                 */
60445679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
60545679Sbostic 
acpinit(unit)60645679Sbostic acpinit(unit)
60745679Sbostic int unit;
60845679Sbostic   {
60945679Sbostic     register struct acp_softc *ds = &acp_softc[unit];
61045679Sbostic     register struct acp_cb *dc;
61145679Sbostic     register struct uba_device *ui = acpinfo[unit];
61245679Sbostic #ifdef FOURTWO
61345679Sbostic     struct sockaddr_in *sin;
61445679Sbostic #else
61545679Sbostic     struct ifaddr *ifa = ds->acp_if.if_addrlist;
61645679Sbostic #endif
61745679Sbostic     int lcn, s;
61845679Sbostic 
61945679Sbostic #ifdef ACPDEBUG
62045679Sbostic if (acp_debug > 0)
62145679Sbostic   {
62245679Sbostic       printf("acp%d: acpinit()\n", unit);
62345679Sbostic   }
62445679Sbostic #endif ACPDEBUG
62545679Sbostic 
62645679Sbostic #ifdef FOURTWO
62745679Sbostic     sin = (struct sockaddr_in *)&ds->acp_if.if_addr;
62845679Sbostic     if (in_netof(sin->sin_addr) == 0)
62945679Sbostic #else
63045679Sbostic ifa = ds->acp_if.ifaddrlist;
63145679Sbostic #ifdef AF_LINK
63245679Sbostic for (; ifa; ifa = ifa->ifa_next)
63345679Sbostic     if (ifa->ifa_addr->sa_family != AF_LINK)
63445679Sbostic 	break;
63545679Sbostic #endif
63645679Sbostic if (    ifa == 0)    /* if we have no internet addr */
63745679Sbostic #endif
63845679Sbostic 	return;
63945679Sbostic     if ((ds->acp_flags & ACPF_OK) == 0)	/* or if ACP not operational */
64045679Sbostic 	return;				/*   don't init */
64145679Sbostic 
64245679Sbostic 
64345679Sbostic     dc = ds->acp_cb;			/* setup ptr to first LCN cntl block */
64445679Sbostic 
64545679Sbostic     for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++)	/* for all LCN's ... */
64645679Sbostic       {
64745679Sbostic     	dc->dc_lcn = lcn;		/* record LCN */
64845679Sbostic 
64945679Sbostic 		/* init LCN output queue */
65045679Sbostic 
65145679Sbostic     	dc->dc_oq.ifq_head = (struct mbuf *)0;
65245679Sbostic     	dc->dc_oq.ifq_tail = (struct mbuf *)0;
65345679Sbostic     	dc->dc_oq.ifq_len = 0;
65445679Sbostic     	dc->dc_oq.ifq_maxlen = ACP_OQMAX;
65545679Sbostic     	dc->dc_oq.ifq_drops = 0;
65645679Sbostic 
65745679Sbostic     		/* init HDX channels */
65845679Sbostic 
65945679Sbostic     	dc->dc_rchan.hc_next = (struct hdx_chan *)0;
66045679Sbostic     	dc->dc_rchan.hc_chan = lcn * 2;
66145679Sbostic     	dc->dc_wchan.hc_next = (struct hdx_chan *)0;
66245679Sbostic     	dc->dc_wchan.hc_chan = (lcn * 2) + 1;
66345679Sbostic 
66445679Sbostic     		/* init UNIBUS resources, allocate UNIBUS map registers */
66545679Sbostic 
66645679Sbostic     	if ((ds->acp_if.if_flags & IFF_RUNNING) == 0)
66745679Sbostic           {
66845679Sbostic     	    if (if_ubainit(&dc->dc_ifuba, ui->ui_ubanum,
66945679Sbostic     	      0, (int)btoc(ACPMTU)) == 0)
67045679Sbostic     	      {
67145679Sbostic     	        printf("acp%d: failed getting UBA resources for lcn %d\n",
67245679Sbostic     		  unit, lcn);
67345679Sbostic     	        ds->acp_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
67445679Sbostic     	        return;
67545679Sbostic     	      }
67645679Sbostic 	  }
67745679Sbostic     	dc->dc_flags = 0;		/* initialize flags */
67845679Sbostic 
67945679Sbostic 	dc++;				/* point at next cntl blk */
68045679Sbostic       }
68145679Sbostic 
68245679Sbostic     ds->acp_sioq.sq_head = (struct hdx_chan *)0;
68345679Sbostic     ds->acp_sioq.sq_tail = (struct hdx_chan *)0;
68445679Sbostic     ds->acp_if.if_flags |= IFF_RUNNING;
68545679Sbostic 
68645679Sbostic     s = splimp();			/* disable interrupts        */
68745679Sbostic 
68845679Sbostic     dc = ds->acp_cb;			/* setup ptr to first LCN cntl block */
68945679Sbostic 
69045679Sbostic     for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++)	/* issue reads on all LCNs */
69145679Sbostic       {
69245679Sbostic     	acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
69345679Sbostic 	dc++;
69445679Sbostic       }
69545679Sbostic 
69645679Sbostic 	/* if not already established, allocate control and data paths  */
69745679Sbostic 
69845679Sbostic     if ((ds->acp_path & ACP_SUPR) == 0)
69945679Sbostic         acp_alloc(ds, TYPE_CNTL);	/* allocate control path  */
70045679Sbostic     if ((ds->acp_path & ACP_DATA) == 0)
70145679Sbostic         acp_alloc(ds, TYPE_DATA);	/* allocate data path     */
70245679Sbostic 
70345679Sbostic     if ((ds->acp_path & INIT_OK) == INIT_OK)
70445679Sbostic       {
70545679Sbostic         acp_init(ds);			/* init the ACP, if ioctl to do so */
70645679Sbostic     	ds->acp_path &= ~INIT_OK;	/* turn off flag for acpinit() */
70745679Sbostic       }
70845679Sbostic 
70945679Sbostic     splx(s);				/* enable interrupts        */
71045679Sbostic 
71145679Sbostic #ifdef FOURTWO
71245679Sbostic     if_rtinit(&ds->acp_if, RTF_UP);	/* initialize the routing table entry */
71345679Sbostic 					/*  according to the network, args    */
71445679Sbostic 					/*  are the addr of the ifnet struct  */
71545679Sbostic 					/*  and RTF_UP means the route is     */
71645679Sbostic 					/*  useable                           */
71745679Sbostic #endif
71845679Sbostic   }
71945679Sbostic 
72045679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
72145679Sbostic /*%%                      ACPOUTPUT()                            %%*/
72245679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
72345679Sbostic /*                                                                 */
72445679Sbostic /*  Purpose:                                                       */
72545679Sbostic /*                                                                 */
72645679Sbostic /*   This routine is called by the network software when it has an */
72745679Sbostic /*   IP datagram to send out this interface.  The datagtram is     */
72845679Sbostic /*   queued for output on that LCN.                                */
72945679Sbostic /*                                                                 */
73045679Sbostic /*  Call:            acpoutput(ifp, m0, dst)                       */
73145679Sbostic /*  Arguments:       ifp:  locates the network interface, ifnet    */
73245679Sbostic /*                   m0:   locates an mbuf buffer                  */
73345679Sbostic /*                   dst:  is the socket destination address       */
73445679Sbostic /*  Returns:         0 for success, or one of following nonzero    */
73545679Sbostic /*                        error indications:                       */
73645679Sbostic /*                               ENETDOWN                          */
73745679Sbostic /*                               EAFNOSUPPORT                      */
73845679Sbostic /*                               ENOBUFS                           */
73945679Sbostic /*  Called by:     network software, address of this routine is    */
74045679Sbostic /*                 defined in the acp_if network interface struct  */
74145679Sbostic /*  Calls to:      printf()                                        */
74245679Sbostic /*                 mfreem()                                        */
74345679Sbostic /*                 splimp()                                        */
74445679Sbostic /*                 IF_QFULL()                                      */
74545679Sbostic /*                 IF_DROP()                                       */
74645679Sbostic /*                 splx()                                          */
74745679Sbostic /*                 IF_ENQUEUE()                                    */
74845679Sbostic /*                 m_freem()                                       */
74945679Sbostic /*                 acp_start()                                     */
75045679Sbostic /*                                                                 */
75145679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
75245679Sbostic 
75345679Sbostic acpoutput(ifp, m0, dst)
75445679Sbostic struct ifnet *ifp;		/* network interface          */
75545679Sbostic struct mbuf *m0;		/* buffer                     */
75645679Sbostic struct sockaddr_in *dst;	/* socket destination address */
75745679Sbostic   {
75845679Sbostic     register struct mbuf *m = m0;
75945679Sbostic     register struct acp_softc *ds = &acp_softc[ifp->if_unit];
76045679Sbostic     register struct acp_cb *dc;
76145679Sbostic     register struct ifqueue *oq;
76245679Sbostic     struct mbuf *prev;
76345679Sbostic     int s;
76445679Sbostic 
76545679Sbostic     if ((ds->acp_if.if_flags & IFF_UP) == 0)
76645679Sbostic 	return (ENETDOWN);
76745679Sbostic 
76845679Sbostic     switch (dst->sin_family)
76945679Sbostic       {
77045679Sbostic 
77145679Sbostic #ifdef INET
77245679Sbostic     case AF_INET:		/* address format of protocol family */
77345679Sbostic 				/*  this is the internet:  TCP, UDP, */
77445679Sbostic 				/*  ICMP, IP, etc.                   */
77545679Sbostic 	break;
77645679Sbostic #endif INET
77745679Sbostic 
77845679Sbostic     default:
77945679Sbostic 	printf("acp%d: can't handle af%d\n", ifp->if_unit,
78045679Sbostic 	    dst->sin_family);
78145679Sbostic 	m_freem(m0);
78245679Sbostic 	return (EAFNOSUPPORT);
78345679Sbostic       }
78445679Sbostic 
78545679Sbostic 
78645679Sbostic #ifdef ACPDEBUG
78745679Sbostic if (acp_debug > 6)
78845679Sbostic   {
78945679Sbostic       printf("acpoutput(): dst = ");
79045679Sbostic       prt_addr(dst->sin_addr);
79145679Sbostic       printf("\n");
79245679Sbostic   }
79345679Sbostic #endif ACPDEBUG
79445679Sbostic 
79545679Sbostic     /* In 4.3, the IP code may pass mbuf chains with 0-length mbufs */
79645679Sbostic     /* This causes "transfer count = 0" messages and might even     */
79745679Sbostic     /* cause actual garbage data transmission if the mbuf is at the */
79845679Sbostic     /* end of the chain (we don't think it ever will be, but one    */
79945679Sbostic     /* can't be too sure...so we scan the chain first).		    */
80045679Sbostic     /* WE DO ASSUME that there is at least one nonempty mbuf!	    */
80145679Sbostic 
80245679Sbostic     while (m0->m_len == 0)
80345679Sbostic     {
80445679Sbostic 	m = m0;
80545679Sbostic 	m0 = m0->m_next;
80645679Sbostic 	m->m_next = 0;
80745679Sbostic 	m_freem (m);
80845679Sbostic     }
80945679Sbostic     /* Now we know the first mbuf (at m0)  is not zero length	    */
81045679Sbostic     prev = m0;
81145679Sbostic     m = m0->m_next;
81245679Sbostic     while (m)
81345679Sbostic     {
81445679Sbostic 	if (m->m_len == 0)
81545679Sbostic 	{
81645679Sbostic 	    prev->m_next = m->m_next;
81745679Sbostic 	    m->m_next = 0;
81845679Sbostic 	    m_freem (m);
81945679Sbostic 	    m = prev->m_next;
82045679Sbostic 	}
82145679Sbostic 	else
82245679Sbostic 	{
82345679Sbostic 	    prev = m;
82445679Sbostic 	    m = m->m_next;
82545679Sbostic 	}
82645679Sbostic     }
82745679Sbostic     m = m0;			/* reset m to beginning of modified chain */
82845679Sbostic 
82945679Sbostic     s = splimp();		/* disable interrupts  */
83045679Sbostic 
83145679Sbostic     dc = &(ds->acp_cb[ACP_DATA]);	/*   data channel          */
83245679Sbostic     oq = &(dc->dc_oq);			/*   point to output queue */
83345679Sbostic     if (IF_QFULL(oq))			/*   if q full */
83445679Sbostic       {
83545679Sbostic 	IF_DROP(oq);			/*     drop the data */
83645679Sbostic 	m_freem(m);
83745679Sbostic 	ds->acp_if.if_collisions++;
83845679Sbostic 	splx(s);
83945679Sbostic 	return (ENOBUFS);
84045679Sbostic       }
84145679Sbostic     IF_ENQUEUE(oq, m);			/*   otherwise queue it */
84245679Sbostic     acp_start(ds, dc);			/*   and try to output  */
84345679Sbostic     splx(s);				/*   enable interrupts  */
84445679Sbostic     return (0);				/*   successful return  */
84545679Sbostic   }
84645679Sbostic 
84745679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
84845679Sbostic /*%%                      ACPIOCTL()                             %%*/
84945679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
85045679Sbostic /*                                                                 */
85145679Sbostic /*  Purpose:                                                       */
85245679Sbostic /*                                                                 */
85345679Sbostic /*   This routine processes device dependent ioctl's.  Supported   */
85445679Sbostic /*   ioctls set the host's internet address for this network       */
85545679Sbostic /*   interface, or send CIMs (Command Interface Messages) to the   */
85645679Sbostic /*   ACP (ie to bring up the line).  The logic for setting the     */
85745679Sbostic /*   interface address must remain compatible with both ifconfig   */
85845679Sbostic /*   and acpconfig programs.                                       */
85945679Sbostic /*                                                                 */
86045679Sbostic /*  Call:            acpioctl(ifp, cmd, data)                      */
86145679Sbostic /*  Argument:        ifp:   pointer to the network interface data  */
86245679Sbostic /*                               structure, ifnet                  */
86345679Sbostic /*                   cmd:   identifies the type of ioctl           */
86445679Sbostic /*                   data:  information for the ioctl              */
86545679Sbostic /*  Returns:         0 for success, or the nonzero error value:    */
86645679Sbostic /*                                EINVAL invalid ioctl request     */
86745679Sbostic /*  Called by:        network software, address of this routine is */
86845679Sbostic /*                    defined in af_inet network interface struct  */
86945679Sbostic /*  Calls to:         splimp()                                     */
87045679Sbostic /*                    if_rtinit()                                  */
87145679Sbostic /*                    in_netof()                                   */
87245679Sbostic /*                    in_lnaof()                                   */
87345679Sbostic /*                    acpinit()                                    */
87445679Sbostic /*                    acpreset()                                   */
87545679Sbostic /*                    printf()                                     */
87645679Sbostic /*                    splx()                                       */
87745679Sbostic /*                                                                 */
87845679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
87945679Sbostic 
acpioctl(ifp,cmd,data)88045679Sbostic acpioctl(ifp, cmd, data)
88145679Sbostic register struct ifnet *ifp;	/* network interface data structure      */
88245679Sbostic int cmd;			/* type of ioctl request                 */
88345679Sbostic caddr_t data;			/* address of data for ioctl request     */
88445679Sbostic   {
88545679Sbostic     register struct uba_device *ui = acpinfo[ifp->if_unit];
88645679Sbostic     struct ifreq *ifr = (struct ifreq *)data;	/* ifreq is the interface */
88745679Sbostic 				/* request struct used for socket ioctls  */
88845679Sbostic     struct acp_softc *ds = &acp_softc[ifp->if_unit];
88945679Sbostic     int s = splimp(), error = 0;	/* disable interrupts    */
89045679Sbostic #ifdef FOURTWO
89145679Sbostic     struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
89245679Sbostic #else
89345679Sbostic     struct ifaddr *ifa = ds->acp_if.if_addrlist;
89445679Sbostic #endif
89545679Sbostic 
89645679Sbostic #ifdef ACPDEBUG
89745679Sbostic if (acp_debug > 2)
89845679Sbostic   {
89945679Sbostic       printf("acp%d:  acpioctl()\n", ifp->if_unit);
90045679Sbostic   }
90145679Sbostic #endif ACPDEBUG
90245679Sbostic 
90345679Sbostic     switch (cmd)
90445679Sbostic       {
90545679Sbostic     case SIOCSIFADDR:			/* set ifnet address    */
90645679Sbostic #ifdef FOURTWO
90745679Sbostic 	if (ifp->if_flags & IFF_RUNNING)
90845679Sbostic 	    if_rtinit(ifp, -1);		/* delete previous route */
90945679Sbostic 	ifp->if_addr = *(struct sockaddr *)sin;
91045679Sbostic 	ifp->if_net = in_netof(sin->sin_addr);
91145679Sbostic 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
91245679Sbostic 	if (ifp->if_flags & IFF_RUNNING)
91345679Sbostic 	    if_rtinit(ifp, RTF_UP);	/* RTF_UP means route useable */
91445679Sbostic 	else
91545679Sbostic 	    acpinit(ifp->if_unit);
91645679Sbostic #else
91745679Sbostic         if (ifa->ifa_addr.sa_family != AF_INET)
91845679Sbostic                 return(EINVAL);
91945679Sbostic         if ((ifp->if_flags & IFF_RUNNING) == 0)
92045679Sbostic                 acpinit(ifp->if_unit);
92145679Sbostic         ds->acp_ipaddr = IA_SIN(ifa)->sin_addr;
92245679Sbostic #endif
92345679Sbostic 	break;
92445679Sbostic 
92545679Sbostic     case SIOCACPCONFIG:
92645679Sbostic 	/* if not trying to bring down link (case '0') then trying to bring */
92745679Sbostic 	/* it up, or reconfigure it -- don't do cmd unless internet address */
92845679Sbostic 	/* has already been set                                             */
92945679Sbostic 
93045679Sbostic     	if (*(ifr->ifr_data) != '0' )
93145679Sbostic 	{
93245679Sbostic #ifdef FOURTWO
93345679Sbostic             sin = (struct sockaddr_in *)&ds->acp_if.if_addr;
93445679Sbostic             if (in_netof(sin->sin_addr) == 0)
93545679Sbostic #else
93645679Sbostic 	    if (ds->acp_if.if_addrlist == 0)
93745679Sbostic #endif
93845679Sbostic 	    {
93945679Sbostic 	        printf("acp%d:  no internet address is set,", ifp->if_unit);
94045679Sbostic 	        printf(" acpconfig command ignored\n");
94145679Sbostic 	        goto exit;
94245679Sbostic 	    }
94345679Sbostic   	}
94445679Sbostic   	acpreset(ifp->if_unit, ui->ui_ubanum); /* reset device */
94545679Sbostic     	ds->acp_path |= INIT_OK;	/* set flag for acpinit() */
94645679Sbostic 
94745679Sbostic 	/* if command is set the baud rate, then set clocking for  */
94845679Sbostic 	/* internal generation, and look up the value for the baud */
94945679Sbostic 	/* rate divisor in the baud_rate table, put this value in  */
95045679Sbostic 	/* the Set System Parameters message, ssp_msg              */
95145679Sbostic 
95245679Sbostic 	if ( (*(ifr->ifr_data) >= 1) && (*(ifr->ifr_data) <= 14) )
95345679Sbostic 	{
95445679Sbostic 	    register struct baud *p;
95545679Sbostic 
95645679Sbostic   	    ssp_msg[CLOCK_OFFSET] = INTERNAL_CLOCK;
95745679Sbostic 
95845679Sbostic 	    for (p = baud_rate; p->b_value; p++)
95945679Sbostic 		{
96045679Sbostic 	        if ((*(ifr->ifr_data) - p->b_value) == 0)
96145679Sbostic 		    break;
96245679Sbostic 		}
96345679Sbostic 	    ssp_msg[BAUD_OFFSET] = p->parameter1;
96445679Sbostic 	    ssp_msg[BAUD_OFFSET + 1] = p->parameter2;
96545679Sbostic 	    if (p->b_value == 0)
96645679Sbostic 	    {
96745679Sbostic 		printf("acp%d: invalid value for baud rate\n", ifp->if_unit);
96845679Sbostic 		goto exit;
96945679Sbostic 	    }
97045679Sbostic 	}
97145679Sbostic 	else
97245679Sbostic 	{
97345679Sbostic     	    switch (*(ifr->ifr_data))
97445679Sbostic             {
97545679Sbostic     	        case '0':
97645679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_DISABLE;
97745679Sbostic         	    break;
97845679Sbostic     	        case '1':
97945679Sbostic   		    ssp_msg[LOOP_OFFSET] = LOOP_NONE;
98045679Sbostic   		    ssp_msg[DTE_OFFSET] = DTE_MODE;
98145679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
98245679Sbostic 		    break;
98345679Sbostic     	        case '2':
98445679Sbostic   		    ssp_msg[LOOP_OFFSET] = LOOP_NONE;
98545679Sbostic   		    ssp_msg[DTE_OFFSET] = DCE_MODE;
98645679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
98745679Sbostic 		    break;
98845679Sbostic     	        case '3':
98945679Sbostic   		    ssp_msg[LOOP_OFFSET] = LOOP_EXTERNAL;
99045679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
99145679Sbostic         	    break;
99245679Sbostic     	        case '4':
99345679Sbostic   		    ssp_msg[LOOP_OFFSET] = LOOP_INTERNAL;
99445679Sbostic   		    ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
99545679Sbostic         	    break;
99645679Sbostic     	        case 'b':
99745679Sbostic   		    ssp_msg[CLOCK_OFFSET] = EXTERNAL_CLOCK;
99845679Sbostic         	    break;
99945679Sbostic                 default:
100045679Sbostic 		    error = EINVAL;
100145679Sbostic 		    goto exit;
100245679Sbostic               }
100345679Sbostic 	 }
100445679Sbostic   	 acpinit(ifp->if_unit);		/* send ssp_msg to frontend */
100545679Sbostic          break;
100645679Sbostic 
100745679Sbostic     default:
100845679Sbostic 	error = EINVAL;
100945679Sbostic     }
101045679Sbostic 
101145679Sbostic exit:
101245679Sbostic     splx(s);				/* enable interrupts   */
101345679Sbostic     return (error);
101445679Sbostic   }
101545679Sbostic 
101645679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
101745679Sbostic /*%%                      ACPINTA()                              %%*/
101845679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
101945679Sbostic /*                                                                 */
102045679Sbostic /*  Purpose:                                                       */
102145679Sbostic /*                                                                 */
102245679Sbostic /*  This is the interrupt handler for I/O interrupts from the ACP  */
102345679Sbostic /*  The I/O mailboxes are scanned for handshake events to process. */
102445679Sbostic /*  The events are Transfer Request, I/O Request done and I/O      */
102545679Sbostic /*  Completion ready.  Note that the Transfer Request is not yet   */
102645679Sbostic /*  supported; an error message is printed if one is received.     */
102745679Sbostic /*                                                                 */
102845679Sbostic /*  Call:           acpinta(unit)                                  */
102945679Sbostic /*  Argument:       unit:  ACP device unit number                  */
103045679Sbostic /*  Returns:        nothing                                        */
103145679Sbostic /*  Called by:      network software, address of this routine is   */
103245679Sbostic /*                  defined in af_inet network interface struct    */
103345679Sbostic /*  Calls to:       printf()                                       */
103445679Sbostic /*                  start_chn()                                    */
103545679Sbostic /*                  acp_data()                                     */
103645679Sbostic /*                  acp_supr()                                     */
103745679Sbostic /*                                                                 */
103845679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
103945679Sbostic 
acpinta(unit)104045679Sbostic acpinta(unit)
104145679Sbostic int unit;
104245679Sbostic   {
104345679Sbostic     register struct acpregs *addr = (struct acpregs *)acpinfo[unit]->ui_addr;
104445679Sbostic     register struct acp_softc *ds = &acp_softc[unit];
104545679Sbostic     register struct hdx_chan *hc;
104645679Sbostic     int chan, cc, cnt;
104745679Sbostic 
104845679Sbostic #ifdef ACPDEBUG
104945679Sbostic if (acp_debug > 7)
105045679Sbostic   {
105145679Sbostic       printf("acp%d: acpinta()\n", unit);
105245679Sbostic   }
105345679Sbostic #endif ACPDEBUG
105445679Sbostic 
105545679Sbostic     /* Figure out what kind of interrupt it was */
105645679Sbostic 
105745679Sbostic     if (addr->xfr_flags & FLAGS_RDY)	/* Transfer Request Mailbox */
105845679Sbostic       {
105945679Sbostic 	printf("acp%d: UNEXPECTED TRANSFER REQUEST!\n", unit);
106045679Sbostic 	addr->xfr_cnt = 0;
106145679Sbostic 	addr->xfr_flags = (addr->xfr_flags & ~FLAGS_RDY) | FLAGS_DON;
106245679Sbostic 	addr->csr |= CSR_INTRA;
106345679Sbostic       }
106445679Sbostic 
106545679Sbostic     if (addr->req_flags & FLAGS_DON)	/* I/O Request Mailbox  */
106645679Sbostic       {
106745679Sbostic     	/* try to start any queued i/o request */
106845679Sbostic 
106945679Sbostic     	if (ds->acp_sioq.sq_head = ds->acp_sioq.sq_head->hc_next)
107045679Sbostic     	  {
107145679Sbostic     	    start_chn(ds);
107245679Sbostic     	  }
107345679Sbostic 	else
107445679Sbostic 	  {
107545679Sbostic 	    addr->req_flags &= ~FLAGS_DON;
107645679Sbostic 	  }
107745679Sbostic       }
107845679Sbostic 
107945679Sbostic     if (addr->cmp_flags & FLAGS_RDY)	/* I/O Completion  Mailbox */
108045679Sbostic       {
108145679Sbostic 
108245679Sbostic 	/*
108345679Sbostic 	 * Get logical channel info.
108445679Sbostic 	 */
108545679Sbostic 	if ((chan = addr->cmp_chan) > NACPCH)
108645679Sbostic           {
108745679Sbostic 	    printf("acp%d: unknown channel, chan=%d\n", unit, chan);
108845679Sbostic 	    return;
108945679Sbostic 	  }
109045679Sbostic 
109145679Sbostic 	if (addr->cmp_flags & FLAGS_DIR)
109245679Sbostic     	    hc = &(ds->acp_cb[chan].dc_wchan);
109345679Sbostic 	else
109445679Sbostic     	    hc = &(ds->acp_cb[chan].dc_rchan);
109545679Sbostic 	cc = addr->cmp_stat;	/* Mailbox I/O completion status      */
109645679Sbostic 	cnt = addr->cmp_cnt;	/* Mailbox I/O completion byte count  */
109745679Sbostic 
109845679Sbostic     	switch (cc)	/* check for unsuccessful I/O completion status */
109945679Sbostic     	  {
110045679Sbostic     	case ACPIOCABT:
110145679Sbostic     	    printf("acp%d: I/O abort ", unit);
110245679Sbostic     	    goto daterr;
110345679Sbostic 
110445679Sbostic     	case ACPIOCERR:
110545679Sbostic     	    printf("acp%d: program error ", unit);
110645679Sbostic     	    goto daterr;
110745679Sbostic 
110845679Sbostic     	case ACPIOCOVR:
110945679Sbostic     	    printf("acp%d: overrun error ", unit);
111045679Sbostic     	    goto daterr;
111145679Sbostic 
111245679Sbostic     	case ACPIOCUBE:
111345679Sbostic     	    printf("acp%d: NXM timeout or UB parity error ", unit);
111445679Sbostic 
111545679Sbostic     	daterr:
111645679Sbostic     	    printf("chan=%d func=%x\n", chan, hc->hc_func);
111745679Sbostic     	    if (addr->cmp_flags & FLAGS_DIR)
111845679Sbostic     		ds->acp_if.if_oerrors++;
111945679Sbostic     	    else
112045679Sbostic     		ds->acp_if.if_ierrors++;
112145679Sbostic     	  }
112245679Sbostic 
112345679Sbostic     	/* was it supervisor or data traffic? */
112445679Sbostic 
112545679Sbostic     	if (chan > ACP_SUPR)
112645679Sbostic     	    acp_data(ds, hc, cc, cnt);
112745679Sbostic     	else
112845679Sbostic     	    acp_supr(ds, hc, cc, cnt, chan);  /* chan = ACP_ALLOC or ACP_SUPR */
112945679Sbostic 
113045679Sbostic     	/*
113145679Sbostic     	 * Ack the interrupt.  Fix the Mailbox Ready and Done bits:  set
113245679Sbostic          * DON bits, and clear RDY bits so mailbox may be reused.
113345679Sbostic     	 */
113445679Sbostic     	addr->cmp_flags = (addr->cmp_flags & ~FLAGS_RDY) | FLAGS_DON;
113545679Sbostic 	addr->csr |= CSR_INTRA;			/* enable interrupt "a" */
113645679Sbostic 
113745679Sbostic       }
113845679Sbostic   }
113945679Sbostic 
114045679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
114145679Sbostic /*%%                      ACPINTB()                              %%*/
114245679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
114345679Sbostic /*                                                                 */
114445679Sbostic /*  Purpose:                                                       */
114545679Sbostic /*                                                                 */
114645679Sbostic /*   This is the interrupt handler for system interrupts from the  */
114745679Sbostic /*   ACP.                                                          */
114845679Sbostic /*                                                                 */
114945679Sbostic /*  Call:             acpintb(unit)                                */
115045679Sbostic /*  Argument:         unit: ACP device unit number                 */
115145679Sbostic /*  Returns:          nothing                                      */
115245679Sbostic /*  Called by:        network software, address of this routine is */
115345679Sbostic /*                    defined in af_inet network interface struct  */
115445679Sbostic /*  Calls to:         printf()                                     */
115545679Sbostic /*                    acpinit()                                    */
115645679Sbostic /*                                                                 */
115745679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
115845679Sbostic 
acpintb(unit)115945679Sbostic acpintb(unit)
116045679Sbostic int unit;
116145679Sbostic   {
116245679Sbostic     register struct acpregs *addr = (struct acpregs *)acpinfo[unit]->ui_addr;
116345679Sbostic     register struct acp_softc *ds = &acp_softc[unit];
116445679Sbostic 
116545679Sbostic #ifdef ACPDEBUG
116645679Sbostic if (acp_debug > 1)
116745679Sbostic   {
116845679Sbostic       printf("acp%d: acpintb()\n", unit);
116945679Sbostic   }
117045679Sbostic #endif ACPDEBUG
117145679Sbostic 
117245679Sbostic     if (ds->acp_flags & ACPF_OK)
117345679Sbostic       {
117445679Sbostic 	printf("acp%d: Unexpected System interrupt, status = %d\n",
117545679Sbostic 	    unit, addr->sys_stat);
117645679Sbostic 	addr->csr = 0;
117745679Sbostic 	printf("acp%d: DISABLED!\n", unit);
117845679Sbostic 	ds->acp_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
117945679Sbostic       }
118045679Sbostic     else
118145679Sbostic       {
118245679Sbostic 	if (addr->sys_stat != ACPSTAT_OK)
118345679Sbostic 	  {
118445679Sbostic 	    printf("acp%d: PWRUP Diagnostic failure = %d\n",
118545679Sbostic 		unit, addr->sys_stat);
118645679Sbostic 	    addr->csr = 0;
118745679Sbostic 	  }
118845679Sbostic 	else
118945679Sbostic 	  {
119045679Sbostic 	    ds->acp_flags |= ACPF_OK;
119145679Sbostic 	    addr->csr |= (CSR_IENA | CSR_DMAEN);
119245679Sbostic 	    acpinit(unit);
119345679Sbostic 	  }
119445679Sbostic       }
119545679Sbostic   }
119645679Sbostic 
119745679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
119845679Sbostic /*%%                                                             %%*/
119945679Sbostic /*%%                   LOCAL  ROUTINES                           %%*/
120045679Sbostic /*%%                                                             %%*/
120145679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
120245679Sbostic 
120345679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
120445679Sbostic /*%%                      ACP_ALLOC()                            %%*/
120545679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
120645679Sbostic /*                                                                 */
120745679Sbostic /*  Purpose:                                                       */
120845679Sbostic /*                                                                 */
120945679Sbostic /*   This routine allocates control or data paths.  Commands are   */
121045679Sbostic /*   sent (over DPN 0) from the host to the ALLOC facility on the  */
121145679Sbostic /*   front end to allocate the paths.  The ALLOC facility returns  */
121245679Sbostic /*   a response to the allocation command which indicates success  */
121345679Sbostic /*   or failure.  Note that DPN 0 is used only for the ALLOC       */
121445679Sbostic /*   commands, and is not a control path as it was been in the     */
121545679Sbostic /*   past.  The paths are symbolically defined as ACP_ALLOC,       */
121645679Sbostic /*   ACP_SUPR, and ACP_DATA for allocation messages, control       */
121745679Sbostic /*   messages, and data respectively.  The CID field indicates     */
121845679Sbostic /*   the data path number of the allocation command.  The CID      */
121945679Sbostic /*   is set here so that the response will have the same CID, and  */
122045679Sbostic /*   will therefore indicate to which path the response            */
122145679Sbostic /*   corresponds. (The CID is set in the command and must be       */
122245679Sbostic /*   returned, untouched, in the response.)                        */
122345679Sbostic /*                                                                 */
122445679Sbostic /*  Call:          acp_alloc(ds, type)                             */
122545679Sbostic /*  Argument:      ds:  pointer to ACP device control structure    */
122645679Sbostic /*                 type:  specifies if path is for control or data */
122745679Sbostic /*  Returns:       nothing                                         */
122845679Sbostic /*  Called by:     acpinit()                                       */
122945679Sbostic /*  Calls to:          MGET()                                      */
123045679Sbostic /*                     printf()                                    */
123145679Sbostic /*                     mtod()                                      */
123245679Sbostic /*                     bcopy()                                     */
123345679Sbostic /*                     sizeof()                                    */
123445679Sbostic /*                     IF_ENQUEUE()                                */
123545679Sbostic /*                     acp_start()                                 */
123645679Sbostic /*                                                                 */
123745679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
123845679Sbostic 
acp_alloc(ds,type)123945679Sbostic static void acp_alloc(ds, type)
124045679Sbostic struct acp_softc *ds;
124145679Sbostic int type;
124245679Sbostic   {
124345679Sbostic     struct mbuf *m;
124445679Sbostic     register u_char *bp;
124545679Sbostic 
124645679Sbostic #ifdef ACPDEBUG
124745679Sbostic if (acp_debug > 4)
124845679Sbostic   {
124945679Sbostic       printf("acp%d: acp_alloc()\n", ds->acp_if.if_unit);
125045679Sbostic   }
125145679Sbostic #endif ACPDEBUG
125245679Sbostic 
125345679Sbostic     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get init buffer */
125445679Sbostic     if (m == 0)
125545679Sbostic       {
125645679Sbostic     	printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
125745679Sbostic     	return;
125845679Sbostic       }
125945679Sbostic 
126045679Sbostic 	/* modify the path allocation message to get a control path */
126145679Sbostic 	/* or a data path                                           */
126245679Sbostic 
126345679Sbostic     if (type == TYPE_CNTL)
126445679Sbostic       {
126545679Sbostic         alloc_msg[CID_OFFSET] = ACP_SUPR;	/* set CID for response */
126645679Sbostic         alloc_msg[DPN_OFFSET] = ACP_SUPR;	/* path number          */
126745679Sbostic         alloc_msg[TYPE_OFFSET] = TYPE_CNTL;	/* path type = control  */
126845679Sbostic       }
126945679Sbostic     else
127045679Sbostic       {
127145679Sbostic         alloc_msg[CID_OFFSET] = ACP_DATA;	/* set CID for response  */
127245679Sbostic         alloc_msg[DPN_OFFSET] = ACP_DATA;	/* path number           */
127345679Sbostic         alloc_msg[TYPE_OFFSET] = TYPE_DATA;	/* path type = data      */
127445679Sbostic       }
127545679Sbostic 
127645679Sbostic     bp = mtod(m, u_char *);		/* point to data section of mbuf */
127745679Sbostic 
127845679Sbostic     bcopy(alloc_msg, bp, sizeof(alloc_msg));  /* set sys params msg in mbuf */
127945679Sbostic 
128045679Sbostic #ifdef ACPDEBUG
128145679Sbostic if (acp_debug > 5)
128245679Sbostic   {
128345679Sbostic printf("acp_alloc():  ");
128445679Sbostic prt_bytes(bp, sizeof(alloc_msg));   /* print 12-byte header + data */
128545679Sbostic printf("\n");
128645679Sbostic   }
128745679Sbostic #endif ACPDEBUG
128845679Sbostic 
128945679Sbostic 
129045679Sbostic     m->m_len = sizeof(alloc_msg);		/* set msg length */
129145679Sbostic 
129245679Sbostic     IF_ENQUEUE(&(ds->acp_cb[ACP_ALLOC].dc_oq), m);	/* output queue   */
129345679Sbostic 
129445679Sbostic     acp_start(ds, &(ds->acp_cb[ACP_ALLOC]));	/* start ouput of data  */
129545679Sbostic   }
129645679Sbostic 
129745679Sbostic 
129845679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
129945679Sbostic /*%%                      ACP_INIT()                             %%*/
130045679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
130145679Sbostic /*                                                                 */
130245679Sbostic /*  Purpose:                                                       */
130345679Sbostic /*                                                                 */
130445679Sbostic /*   This routine builds and sends an initialization message to    */
130545679Sbostic /*   the ACP.  A canned Set System Parameters Message is sent to   */
130645679Sbostic /*   start HDLC.                                                   */
130745679Sbostic /*                                                                 */
130845679Sbostic /*  Call:          acp_init(ds)                                    */
130945679Sbostic /*  Argument:      ds:  pointer to ACP device control structure    */
131045679Sbostic /*  Returns:                nothing                                */
131145679Sbostic /*  Called by:         acpinit()                                   */
131245679Sbostic /*  Calls to:          MGET()                                      */
131345679Sbostic /*                     printf()                                    */
131445679Sbostic /*                     mtod()                                      */
131545679Sbostic /*                     bcopy()                                     */
131645679Sbostic /*                     sizeof()                                    */
131745679Sbostic /*                     IF_ENQUEUE()                                */
131845679Sbostic /*                     acp_start()                                 */
131945679Sbostic /*                                                                 */
132045679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
132145679Sbostic 
acp_init(ds)132245679Sbostic static void acp_init(ds)
132345679Sbostic struct acp_softc *ds;
132445679Sbostic   {
132545679Sbostic     struct mbuf *m;
132645679Sbostic     register u_char *bp;
132745679Sbostic 
132845679Sbostic #ifdef ACPDEBUG
132945679Sbostic if (acp_debug > 5)
133045679Sbostic   {
133145679Sbostic       printf("acp%d: acp_init()\n", ds->acp_if.if_unit);
133245679Sbostic   }
133345679Sbostic #endif ACPDEBUG
133445679Sbostic 
133545679Sbostic     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get init buffer */
133645679Sbostic     if (m == 0)
133745679Sbostic       {
133845679Sbostic     	printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
133945679Sbostic     	return;
134045679Sbostic       }
134145679Sbostic 
134245679Sbostic     bp = mtod(m, u_char *);		/* point to data section of mbuf */
134345679Sbostic 
134445679Sbostic     bcopy(ssp_msg, bp, sizeof(ssp_msg));  /* put msg into mbuf */
134545679Sbostic 
134645679Sbostic #ifdef ACPDEBUG
134745679Sbostic if (acp_debug > 4)
134845679Sbostic   {
134945679Sbostic printf("acp_init():  ssp msg\n");
135045679Sbostic prt_bytes(bp, sizeof(ssp_msg));		/* print 12-byte header + data */
135145679Sbostic printf("\n");
135245679Sbostic   }
135345679Sbostic #endif ACPDEBUG
135445679Sbostic 
135545679Sbostic     m->m_len = sizeof(ssp_msg);		/* set msg length */
135645679Sbostic 
135745679Sbostic     IF_ENQUEUE(&(ds->acp_cb[ACP_SUPR].dc_oq), m);	/* output queue   */
135845679Sbostic 
135945679Sbostic     acp_start(ds, &(ds->acp_cb[ACP_SUPR]));	/* start ouput of data  */
136045679Sbostic   }
136145679Sbostic 
136245679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
136345679Sbostic /*%%                      ACP_START()                            %%*/
136445679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
136545679Sbostic /*                                                                 */
136645679Sbostic /*  Purpose:                                                       */
136745679Sbostic /*                                                                 */
136845679Sbostic /*    This routine attempts to start output of data queued on a    */
136945679Sbostic /*    specific LCN.  If the LCN was not already busy and data is   */
137045679Sbostic /*    available for output, the data is copied into the LCN's I/O  */
137145679Sbostic /*    buffer and an I/O request queued to the ACP.                 */
137245679Sbostic /*                                                                 */
137345679Sbostic /*  Call:              acpstart(ds, dc)                            */
137445679Sbostic /*  Arguments:         ds:  pointer to device control structure    */
137545679Sbostic /*                     dc:  pointer to the Logical Channel control */
137645679Sbostic /*                            block structure                      */
137745679Sbostic /*  Returns:           nothing                                     */
137845679Sbostic /*  Called by:         acpoutput()                                 */
137945679Sbostic /*                     acp_init()                                  */
138045679Sbostic /*                     acp_data()                                  */
138145679Sbostic /*                     acp_supr()                                  */
138245679Sbostic /*  Calls to:          IF_DEQUEUE()                                */
138345679Sbostic /*                     if_wubaput()                                */
138445679Sbostic /*                     acp_ioreqs()                                */
138545679Sbostic /*                                                                 */
138645679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
138745679Sbostic 
acp_start(ds,dc)138845679Sbostic static void acp_start(ds, dc)
138945679Sbostic register struct acp_softc *ds;
139045679Sbostic register struct acp_cb *dc;
139145679Sbostic   {
139245679Sbostic     register struct mbuf *m;
139345679Sbostic     int len;
139445679Sbostic 
139545679Sbostic     /*
139645679Sbostic      * If output isn't active, attempt to
139745679Sbostic      * start sending a new packet.
139845679Sbostic      */
139945679Sbostic 
140045679Sbostic #ifdef ACPDEBUG
140145679Sbostic if (acp_debug > 7)
140245679Sbostic   {
140345679Sbostic       printf("acp: acp_start()\n");
140445679Sbostic   }
140545679Sbostic #endif ACPDEBUG
140645679Sbostic 
140745679Sbostic     if ((dc->dc_flags & DC_OBUSY) || (dc->dc_oq.ifq_len == 0))
140845679Sbostic     	return;
140945679Sbostic 
141045679Sbostic     IF_DEQUEUE(&dc->dc_oq, m);	/* remove data from LCN output queue */
141145679Sbostic 
141245679Sbostic     len = if_wubaput(&dc->dc_ifuba, m);	/* copy data to mapped mem */
141345679Sbostic 
141445679Sbostic     if (len > ds->acp_maxout)
141545679Sbostic       {
141645679Sbostic 
141745679Sbostic #ifdef ACPDEBUG
141845679Sbostic if (acp_debug > 7)
141945679Sbostic   {
142045679Sbostic     printf("acp: %d byte msg sent.\n", len);
142145679Sbostic   }
142245679Sbostic #endif ACPDEBUG
142345679Sbostic 
142445679Sbostic 	ds->acp_maxout = len;
142545679Sbostic       }
142645679Sbostic 
142745679Sbostic     dc->dc_flags |= DC_OBUSY;
142845679Sbostic 
142945679Sbostic     acp_iorq(ds, dc, len, ACPWRT+ACPEOS);	/* build I/O request, enqueue */
143045679Sbostic   }
143145679Sbostic 
143245679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
143345679Sbostic /*%%                      ACP_IORQ()                             %%*/
143445679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
143545679Sbostic /*                                                                 */
143645679Sbostic /*  Purpose:                                                       */
143745679Sbostic /*                                                                 */
143845679Sbostic /*    This routine builds ACP I/O requests and queues them for     */
143945679Sbostic /*    delivery to the ACP. If the ACP I/O request comm regs are    */
144045679Sbostic /*    not busy, the I/O request is passed to the ACP.              */
144145679Sbostic /*                                                                 */
144245679Sbostic /*  Call:            acp_iorq(ds, dc, len, func)                   */
144345679Sbostic /*  Argument:        ds:   pointer to device control block struct  */
144445679Sbostic /*                   dc:   pointer to the Logical Channel control  */
144545679Sbostic /*                                block structure                  */
144645679Sbostic /*                   len:  byte count                              */
144745679Sbostic /*                   func: the function:  read or write            */
144845679Sbostic /*  Returns:         nothing                                       */
144945679Sbostic /*  Called by:         acpinit()                                   */
145045679Sbostic /*                     acp_start()                                 */
145145679Sbostic /*                     acp_data()                                  */
145245679Sbostic /*                     acp_supr()                                  */
145345679Sbostic /*  Calls to:          start_chn()                                 */
145445679Sbostic /*                                                                 */
145545679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
145645679Sbostic 
acp_iorq(ds,dc,len,func)145745679Sbostic static void acp_iorq(ds, dc, len, func)
145845679Sbostic struct acp_softc *ds;
145945679Sbostic struct acp_cb *dc;
146045679Sbostic int len, func;
146145679Sbostic   {
146245679Sbostic     register struct hdx_chan *hc;
146345679Sbostic     register int info;
146445679Sbostic 
146545679Sbostic 
146645679Sbostic #ifdef ACPDEBUG
146745679Sbostic if (acp_debug > 6)
146845679Sbostic       printf("acp: acp_iorq()\n");
146945679Sbostic #endif ACPDEBUG
147045679Sbostic 
147145679Sbostic     /* get appropriate UNIBUS mapping info */
147245679Sbostic 
147345679Sbostic     if ((func & FCN_MASK) == ACPRED)	/* read or write? */
147445679Sbostic       {
147545679Sbostic     	hc = &dc->dc_rchan;		/* read */
147645679Sbostic     	info = dc->dc_ifuba.ifu_r.ifrw_info;
147745679Sbostic       }
147845679Sbostic     else
147945679Sbostic       {
148045679Sbostic     	hc = &dc->dc_wchan;		/* write */
148145679Sbostic     	info = dc->dc_ifuba.ifu_w.ifrw_info;
148245679Sbostic       }
148345679Sbostic 
148445679Sbostic     /* set channel info */
148545679Sbostic 
148645679Sbostic     hc->hc_adx = (u_char)((info & 0x30000) >> 12);	/* address bits 17-16 */
148745679Sbostic     hc->hc_addr = (unsigned short)(info & 0xffff);	/* address bits 15-00 */
148845679Sbostic     hc->hc_cnt = len;					/* byte count         */
148945679Sbostic     hc->hc_func = (u_char)func;				/* I/O function       */
149045679Sbostic 
149145679Sbostic     if (dc->dc_lcn > ACP_SUPR)
149245679Sbostic         hc->hc_sbfc = SBFCN_DATA;		/* I/O subfunction for data */
149345679Sbostic     else
149445679Sbostic         hc->hc_sbfc = SBFCN_SUPR;		/* I/O subfunction for cntrl */
149545679Sbostic 
149645679Sbostic     /*
149745679Sbostic      * If ACP comm regs busy, queue start i/o for later.
149845679Sbostic      */
149945679Sbostic     if (ds->acp_sioq.sq_head)
150045679Sbostic       {
150145679Sbostic     	(ds->acp_sioq.sq_tail)->hc_next = hc;
150245679Sbostic     	ds->acp_sioq.sq_tail = hc;
150345679Sbostic     	hc->hc_next = 0;
150445679Sbostic     	return;
150545679Sbostic       }
150645679Sbostic 
150745679Sbostic     /* start i/o on channel now */
150845679Sbostic 
150945679Sbostic     ds->acp_sioq.sq_head = hc;
151045679Sbostic     ds->acp_sioq.sq_tail = hc;
151145679Sbostic     hc->hc_next = 0;
151245679Sbostic     start_chn(ds);
151345679Sbostic   }
151445679Sbostic 
151545679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
151645679Sbostic /*%%                      START_CHN()                            %%*/
151745679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
151845679Sbostic /*                                                                 */
151945679Sbostic /*  Purpose:                                                       */
152045679Sbostic /*                                                                 */
152145679Sbostic /*    This routine copies ACP I/O requests into the ACP comm regs  */
152245679Sbostic /*    and notifies the ACP.                                        */
152345679Sbostic /*                                                                 */
152445679Sbostic /*  Call:              start_chn(ds)                               */
152545679Sbostic /*  Argument:          ds:  pointer to device control block struct */
152645679Sbostic /*  Returns:           nothing                                     */
152745679Sbostic /*  Called by:         acpinta()                                   */
152845679Sbostic /*                     acp_iorq()                                  */
152945679Sbostic /*  Calls to:          none                                        */
153045679Sbostic /*                                                                 */
153145679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
153245679Sbostic 
start_chn(ds)153345679Sbostic static void start_chn(ds)
153445679Sbostic struct acp_softc *ds;
153545679Sbostic   {
153645679Sbostic     register struct hdx_chan *hc = ds->acp_sioq.sq_head;
153745679Sbostic     register struct acpregs *addr =
153845679Sbostic     	(struct acpregs *)acpinfo[ds->acp_if.if_unit]->ui_addr;
153945679Sbostic 
154045679Sbostic     /*
154145679Sbostic      * Set up comm regs.
154245679Sbostic      */
154345679Sbostic 
154445679Sbostic #ifdef ACPDEBUG
154545679Sbostic if (acp_debug > 7)
154645679Sbostic   {
154745679Sbostic       printf("acp: start_chn()\n");
154845679Sbostic   }
154945679Sbostic #endif ACPDEBUG
155045679Sbostic 
155145679Sbostic     addr->req_chan = hc->hc_chan >> 1;
155245679Sbostic     addr->req_adx = hc->hc_adx;
155345679Sbostic     addr->req_addr = hc->hc_addr;
155445679Sbostic     addr->req_cnt = hc->hc_cnt;
155545679Sbostic     addr->req_fcn = hc->hc_func;
155645679Sbostic     addr->req_sbf = hc->hc_sbfc;
155745679Sbostic     if (hc->hc_chan & 1)
155845679Sbostic 	addr->req_flags = FLAGS_RDY | FLAGS_DIR;
155945679Sbostic     else
156045679Sbostic 	addr->req_flags = FLAGS_RDY;
156145679Sbostic 
156245679Sbostic     addr->csr |= CSR_INTRA;
156345679Sbostic   }
156445679Sbostic 
156545679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
156645679Sbostic /*%%                      ACP_DATA()                             %%*/
156745679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
156845679Sbostic /*                                                                 */
156945679Sbostic /*  Purpose:                                                       */
157045679Sbostic /*                                                                 */
157145679Sbostic /*    This routine is called when a data channel I/O completes.    */
157245679Sbostic /*    If the completion was for a write, an attempt is made to     */
157345679Sbostic /*    start output on the next packet waiting for output on that   */
157445679Sbostic /*    LCN.  If the completion was for a read, the received packet  */
157545679Sbostic /*    is sent to the IP input queue (if no error) and another read */
157645679Sbostic /*    is started on the LCN.                                       */
157745679Sbostic /*                                                                 */
157845679Sbostic /*  Call:              acp_data(ds, hc, cc, rcnt)                  */
157945679Sbostic /*  Arguments:         ds:  pointer to device control block struct */
158045679Sbostic /*                     hc:  pointer to half duplex channel control */
158145679Sbostic /*                               block                             */
158245679Sbostic /*                     cc:  Mailbox I/O completion status          */
158345679Sbostic /*                     rcnt: byte count                            */
158445679Sbostic /*  Returns:           nothing                                     */
158545679Sbostic /*  Called by:         acpinta()                                   */
158645679Sbostic /*  Calls to:          m_freem()                                   */
158745679Sbostic /*                     acp_start()                                 */
158845679Sbostic /*                     if_rubaget()                                */
158945679Sbostic /*                     IF_QFULL()                                  */
159045679Sbostic /*                     IF_DROP()                                   */
159145679Sbostic /*                     IF_ENQUEUE()                                */
159245679Sbostic /*                     schednetisr()                               */
159345679Sbostic /*                     acp_ioreq()                                 */
159445679Sbostic /*                                                                 */
159545679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
159645679Sbostic 
acp_data(ds,hc,cc,rcnt)159745679Sbostic static void acp_data(ds, hc, cc, rcnt)
159845679Sbostic register struct acp_softc *ds;
159945679Sbostic register struct hdx_chan *hc;
160045679Sbostic int cc, rcnt;
160145679Sbostic {
160245679Sbostic     register struct acp_cb *dc = &(ds->acp_cb[hc->hc_chan/2]);
160345679Sbostic     register struct ifqueue *inq = &ipintrq;
160445679Sbostic     register struct mbuf *m;
160545679Sbostic 
160645679Sbostic     if (hc->hc_chan & 0x01)		/* was it read or write? */
160745679Sbostic       {					/*   write, fire up next output */
160845679Sbostic     	ds->acp_if.if_opackets++;
160945679Sbostic 	if (dc->dc_ifuba.ifu_xtofree)
161045679Sbostic 	  {
161145679Sbostic 	    m_freem(dc->dc_ifuba.ifu_xtofree);
161245679Sbostic 	    dc->dc_ifuba.ifu_xtofree = 0;
161345679Sbostic 	  }
161445679Sbostic     	dc->dc_flags &= ~DC_OBUSY;
161545679Sbostic     	acp_start(ds, dc);
161645679Sbostic       }
161745679Sbostic     else				/*   read, process rcvd packet */
161845679Sbostic       {
161945679Sbostic 
162045679Sbostic #ifdef ACPDEBUG
162145679Sbostic if (acp_debug > 6)
162245679Sbostic   {
162345679Sbostic printf("acp: data read completed, cc = %d, cnt = %d\n", cc, rcnt);
162445679Sbostic prt_bytes((u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr), (rcnt < 20 ? rcnt:20));
162545679Sbostic   }
162645679Sbostic #endif ACPDEBUG
162745679Sbostic 
162845679Sbostic     	if (cc == ACPIOCOK)
162945679Sbostic     	  {				 /* Queue good packet for input */
163045679Sbostic     	    ds->acp_if.if_ipackets++;
163145679Sbostic 	    if (rcnt > ds->acp_maxin)
163245679Sbostic 	      {
163345679Sbostic 
163445679Sbostic #ifdef ACPDEBUG
163545679Sbostic if (acp_debug > 4)
163645679Sbostic   {
163745679Sbostic     printf("acp: %d byte msg received.\n", rcnt);
163845679Sbostic   }
163945679Sbostic #endif ACPDEBUG
164045679Sbostic 
164145679Sbostic 		ds->acp_maxin = rcnt;
164245679Sbostic 	      }
164345679Sbostic 				/* call if_rubaget() to pull read data  */
164445679Sbostic 				/*  off the interface, the args are the */
164545679Sbostic 				/*  ifuba struct, the length of data,   */
164645679Sbostic 				/*  and the 0 indicates that no trailer */
164745679Sbostic 				/*  protocol is used                    */
164845679Sbostic     	    m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &(ds->acp_if));
164945679Sbostic     	    if (m)
165045679Sbostic     	      {
165145679Sbostic     		if (IF_QFULL(inq))
165245679Sbostic     		  {
165345679Sbostic     		    IF_DROP(inq);
165445679Sbostic     		    m_freem(m);
165545679Sbostic     		  }
165645679Sbostic     		else
165745679Sbostic     		  {
165845679Sbostic     		    IF_ENQUEUE(inq, m);
165945679Sbostic     		    schednetisr(NETISR_IP);
166045679Sbostic     		  }
166145679Sbostic     	      }
166245679Sbostic     	  }
166345679Sbostic 
166445679Sbostic     	/* hang a new data read */
166545679Sbostic 
166645679Sbostic     	acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
166745679Sbostic 
166845679Sbostic       }
166945679Sbostic   }
167045679Sbostic 
167145679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
167245679Sbostic /*%%                      ACP_RESPONSE()                         %%*/
167345679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
167445679Sbostic /*                                                                 */
167545679Sbostic /*  Purpose:                                                       */
167645679Sbostic /*                                                                 */
167745679Sbostic /*   This routine sends a Control Interface Message (CIM) response */
167845679Sbostic /*   to the front end to indicate that a CIM command from the      */
167945679Sbostic /*   front end was successfully received.  Presently there are two */
168045679Sbostic /*   types of CIM responses sent to the front end:  frame level    */
168145679Sbostic /*   up, and frame level down.  Future applications may send a     */
168245679Sbostic /*   CIM response to DCP CIM commands.  The basic philosophy with  */
168345679Sbostic /*   CIMs is that there is always a paired command/response which  */
168445679Sbostic /*   is exchanged between the host and the front end.              */
168545679Sbostic /*   Currently, the front end does not process the responses from  */
168645679Sbostic /*   the host, they are merely discarded.  The one thing left to   */
168745679Sbostic /*   do in the case that the front end does ever look at these     */
168845679Sbostic /*   responses is to use the same CID (Command ID field, bytes 5   */
168945679Sbostic /*   to 8 of the CIM header) that was present in the command.      */
169045679Sbostic /*                                                                 */
169145679Sbostic /*  Call:          acp_response(ds, response)                      */
169245679Sbostic /*  Argument:      ds:  pointer to ACP device control structure    */
169345679Sbostic /*                 response:  response for CIM command field       */
169445679Sbostic /*                   the response value = command value + 1        */
169545679Sbostic /*  Returns:       nothing                                         */
169645679Sbostic /*  Called by:     supr_msg()                                      */
169745679Sbostic /*  Calls to:          MGET()                                      */
169845679Sbostic /*                     printf()                                    */
169945679Sbostic /*                     mtod()                                      */
170045679Sbostic /*                     bcopy()                                     */
170145679Sbostic /*                     sizeof()                                    */
170245679Sbostic /*                     IF_ENQUEUE()                                */
170345679Sbostic /*                     acp_start()                                 */
170445679Sbostic /*                                                                 */
170545679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
170645679Sbostic 
acp_response(ds,response)170745679Sbostic static void acp_response(ds, response)
170845679Sbostic struct acp_softc *ds;
170945679Sbostic u_char response;
171045679Sbostic   {
171145679Sbostic     struct mbuf *m;
171245679Sbostic     u_char *bp;
171345679Sbostic 
171445679Sbostic     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get init buffer */
171545679Sbostic     if (m == 0)
171645679Sbostic       {
171745679Sbostic     	printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
171845679Sbostic     	return;
171945679Sbostic       }
172045679Sbostic 			/* put response in CIM cmd field */
172145679Sbostic 
172245679Sbostic     response_msg[CMD_OFFSET] = response;
172345679Sbostic 
172445679Sbostic     bp = mtod(m, u_char *);		/* point to data section of mbuf */
172545679Sbostic 
172645679Sbostic     bcopy(response_msg, bp, sizeof(response_msg));  /* put msg in mbuf */
172745679Sbostic 
172845679Sbostic #ifdef ACPDEBUG
172945679Sbostic if (acp_debug > 6)
173045679Sbostic   {
173145679Sbostic printf("acp_response():  ");
173245679Sbostic prt_bytes(bp, sizeof(response_msg));   /* print messge  */
173345679Sbostic printf("\n");
173445679Sbostic   }
173545679Sbostic #endif ACPDEBUG
173645679Sbostic 
173745679Sbostic     m->m_len = sizeof(response_msg);		/* set msg length */
173845679Sbostic 
173945679Sbostic     IF_ENQUEUE(&(ds->acp_cb[ACP_SUPR].dc_oq), m);	/* output queue   */
174045679Sbostic 
174145679Sbostic     acp_start(ds, &(ds->acp_cb[ACP_SUPR]));	/* start ouput of data  */
174245679Sbostic   }
174345679Sbostic 
174445679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
174545679Sbostic /*%%                      ACP_SUPR()                             %%*/
174645679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
174745679Sbostic /*                                                                 */
174845679Sbostic /*  Purpose:                                                       */
174945679Sbostic /*                                                                 */
175045679Sbostic /*    This routine is called when a supervisor I/O completes.      */
175145679Sbostic /*    If the completion was for a write, an attempt is made to     */
175245679Sbostic /*    start output on the next supervisor command waiting for      */
175345679Sbostic /*    output.  If the completion was for a read, the received      */
175445679Sbostic /*    supervisor message is processed and another read is started. */
175545679Sbostic /*                                                                 */
175645679Sbostic /*  Call:              acp_supr(ds, hc, cc, rcnt, channel)         */
175745679Sbostic /*  Argument:          ds:   pointer to dev control block struct   */
175845679Sbostic /*                     hc:   pointer to the Half Duplex cntrl      */
175945679Sbostic /*                                 block structure                 */
176045679Sbostic /*                     cc:   Mailbox I/O completion status         */
176145679Sbostic /*                     rcnt:  byte count, length of data           */
176245679Sbostic /*                     channel:  indicates ACP_ALLOC or ACP_SUPR   */
176345679Sbostic /*  Returns:           nothing                                     */
176445679Sbostic /*  Called by:         acpinta()                                   */
176545679Sbostic /*  Calls to:          m_freem()                                   */
176645679Sbostic /*                     acp_start()                                 */
176745679Sbostic /*                     supr_msg()                                  */
176845679Sbostic /*                     acp_ioreq()                                 */
176945679Sbostic /*                                                                 */
177045679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
177145679Sbostic 
acp_supr(ds,hc,cc,rcnt,chan)177245679Sbostic static void acp_supr(ds, hc, cc, rcnt, chan)
177345679Sbostic register struct acp_softc *ds;
177445679Sbostic register struct hdx_chan *hc;
177545679Sbostic int cc, rcnt, chan;
177645679Sbostic   {
177745679Sbostic     register struct acp_cb *dc = &(ds->acp_cb[chan]);
177845679Sbostic     register u_char *p;
177945679Sbostic 
178045679Sbostic     /* was it read or write? */
178145679Sbostic 
178245679Sbostic     if (hc->hc_chan & 0x01)
178345679Sbostic       {
178445679Sbostic 	if (dc->dc_ifuba.ifu_xtofree)
178545679Sbostic 	  {
178645679Sbostic 	    m_freem(dc->dc_ifuba.ifu_xtofree);
178745679Sbostic 	    dc->dc_ifuba.ifu_xtofree = 0;
178845679Sbostic 	  }
178945679Sbostic     	dc->dc_flags &= ~DC_OBUSY;
179045679Sbostic     	acp_start(ds, dc);
179145679Sbostic       }
179245679Sbostic     else
179345679Sbostic       {
179445679Sbostic 
179545679Sbostic #ifdef ACPDEBUG
179645679Sbostic if (acp_debug > 3)
179745679Sbostic   {
179845679Sbostic printf("acp: acp_supr(), read completed, cc = %d, cnt = %d\n", cc, rcnt);
179945679Sbostic prt_bytes((u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr), rcnt);
180045679Sbostic printf("\n");
180145679Sbostic   }
180245679Sbostic #endif ACPDEBUG
180345679Sbostic 
180445679Sbostic     	if (cc == ACPIOCOK)
180545679Sbostic     	  {
180645679Sbostic     	    p = (u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr);
180745679Sbostic 
180845679Sbostic     	    /* process supervisor message */
180945679Sbostic     	    supr_msg(ds, p);
181045679Sbostic     	  }
181145679Sbostic     	/* hang a new supr read */
181245679Sbostic     	acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
181345679Sbostic       }
181445679Sbostic   }
181545679Sbostic 
181645679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
181745679Sbostic /*%%                      SUPR_MSG()                             %%*/
181845679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
181945679Sbostic /*                                                                 */
182045679Sbostic /*  Purpose:                                                       */
182145679Sbostic /*                                                                 */
182245679Sbostic /*       This routine processes received supervisor messages.      */
182345679Sbostic /*       Depending on the message type, the appropriate action is  */
182445679Sbostic /*       taken.  Note that the RSF field is checked for responses. */
182545679Sbostic /*       The RSF field is 4 bytes long, but ony that least         */
182645679Sbostic /*       significant byte is used.                                 */
182745679Sbostic /*                                                                 */
182845679Sbostic /*  Call:              supr_msg(ds, p)                             */
182945679Sbostic /*  Arguments:         ds:  pointer to dev control block struct    */
183045679Sbostic /*                     p:   pointer to a character array           */
183145679Sbostic /*                              containing the supervisor message  */
183245679Sbostic /*  Returns:           nothing                                     */
183345679Sbostic /*  Called by:         acp_supr()                                  */
183445679Sbostic /*  Calls to:          printf()                                    */
183545679Sbostic /*                     IF_DEQUEUE()                                */
183645679Sbostic /*                     m_freem()                                   */
183745679Sbostic /*                     acp_response()                              */
183845679Sbostic /*                                                                 */
183945679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
184045679Sbostic 
supr_msg(ds,p)184145679Sbostic static void supr_msg(ds, p)
184245679Sbostic struct acp_softc *ds;
184345679Sbostic u_char p[];
184445679Sbostic   {
184545679Sbostic     register struct acp_cb *dc;
184645679Sbostic     register int lcn;
184745679Sbostic     register struct mbuf *m;
184845679Sbostic 
184945679Sbostic     switch (p[3])
185045679Sbostic       {
185145679Sbostic     case RSP_ALLOC:			/*  alloc response   */
185245679Sbostic         if (p[RSF_OFFSET])	/* check if RSF is 0 for success */
185345679Sbostic           {
185445679Sbostic             printf("acp%d:  attempt to allocate path failed ");
185545679Sbostic             printf("rsf field = %x\n", p[RSF_OFFSET]);
185645679Sbostic             return;
185745679Sbostic           }
185845679Sbostic         else
185945679Sbostic           {
186045679Sbostic             if (p[CID_OFFSET] >=  ACP_SUPR  &&  p[CID_OFFSET] <= ACP_DATA )
186145679Sbostic                 ds->acp_path |= p[CID_OFFSET];
186245679Sbostic             else
186345679Sbostic               {
186445679Sbostic                 printf("acp%d:  path allocation ",ds->acp_if.if_unit);
186545679Sbostic                 printf("response contains invalid DPN = %d\n", p[CID_OFFSET]);
186645679Sbostic               }
186745679Sbostic           }
186845679Sbostic         break;
186945679Sbostic 
187045679Sbostic     case RSP_DEALLOC:			/*  dealloc response */
187145679Sbostic         if (p[RSF_OFFSET])	/* check if RSF is 0 for success */
187245679Sbostic           {
187345679Sbostic             printf("acp%d:  attempt to deallocate path failed ");
187445679Sbostic             printf("rsf field = %x\n", p[RSF_OFFSET]);
187545679Sbostic             return;
187645679Sbostic           }
187745679Sbostic         break;
187845679Sbostic 
187945679Sbostic     case RSP_SSP:			/*  set sys parm rsp */
188045679Sbostic         if (p[RSF_OFFSET])	/* check if RSF is 0 for success */
188145679Sbostic           {
188245679Sbostic             printf("acp%d:  attempt to set HDLC system parameters failed\n");
188345679Sbostic             return;
188445679Sbostic           }
188545679Sbostic         break;
188645679Sbostic 
188745679Sbostic     case CMD_FLUP:			/*   frame level up  */
188845679Sbostic 
188945679Sbostic 	/* check that the data path was successfully allocated, we */
189045679Sbostic 	/* know that the control path was successfully allocated   */
189145679Sbostic 	/* otherwise the FLUP command would not have been issued   */
189245679Sbostic 
189345679Sbostic         if ((ds->acp_path & ACP_DATA) == 0)
189445679Sbostic           {
189545679Sbostic             printf("acp%d:  data path was not successfully allocated\n",
189645679Sbostic 			ds->acp_if.if_unit);
189745679Sbostic           }
189845679Sbostic         ds->acp_if.if_flags |= IFF_UP;
189945679Sbostic         printf("acp%d:  frame level up\n", ds->acp_if.if_unit);
190045679Sbostic         acp_response(ds, RSP_FLUP);	/* send response to front end */
190145679Sbostic         break;
190245679Sbostic 
190345679Sbostic     case CMD_FLDWN:			/* frame level down  */
190445679Sbostic         ds->acp_if.if_flags &= ~IFF_UP;
190545679Sbostic         dc = ds->acp_cb;
190645679Sbostic         for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++)	/* for all LCN's */
190745679Sbostic           {
190845679Sbostic             while (dc->dc_oq.ifq_len) /* drop pending data */
190945679Sbostic               {
191045679Sbostic  	        IF_DEQUEUE(&dc->dc_oq, m);
191145679Sbostic     	        m_freem(m);
191245679Sbostic               }
191345679Sbostic 	    dc++;
191445679Sbostic     	  }
191545679Sbostic         printf("acp%d:  frame level down\n", ds->acp_if.if_unit);
191645679Sbostic         acp_response(ds, RSP_FLDWN);	/* send response to front end */
191745679Sbostic     	break;
191845679Sbostic 
191945679Sbostic     default:
192045679Sbostic     	printf("acp%d: supervisor error, code=%x\n",
192145679Sbostic 	   ds->acp_if.if_unit, p[3]);
192245679Sbostic       }
192345679Sbostic   }
192445679Sbostic 
192545679Sbostic 
192645679Sbostic #ifdef ACPDEBUG
192745679Sbostic 
192845679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
192945679Sbostic /*%%                            PRT_ADDR()                             %%*/
193045679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
193145679Sbostic /*                                                                       */
193245679Sbostic /*  Purpose:                                                             */
193345679Sbostic /*                                                                       */
193445679Sbostic /*	This routine is used to print internet addresses in the		 */
193545679Sbostic /*	standard A.B.C.D format.  Note that this routine is for          */
193645679Sbostic /*	debugging purposes (ifdef ACPDEBUG).                             */
193745679Sbostic /*									 */
193845679Sbostic /*  Call:  		prt_addr(addr)                                   */
193945679Sbostic /*  Argument:      	addr:  internet address structure                */
194045679Sbostic /*  Returns:  		nothing                                          */
194145679Sbostic /*  Called by:  	acpoutput()                                      */
194245679Sbostic /*  Calls to:   	printf()                                         */
194345679Sbostic /*									 */
194445679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
194545679Sbostic 
prt_addr(addr)194645679Sbostic static void prt_addr(addr)
194745679Sbostic struct in_addr addr;
194845679Sbostic   {
194945679Sbostic #ifndef FOURTWO
195045679Sbostic         union {
195145679Sbostic                 struct in_addr ip;
195245679Sbostic                 struct {                /* (assume Class A network number) */
195345679Sbostic                         u_char s_net;
195445679Sbostic                         u_char s_host;
195545679Sbostic                         u_char s_lh;
195645679Sbostic                         u_char s_impno;
195745679Sbostic                 } imp;
195845679Sbostic         } imp_addr;
195945679Sbostic         imp_addr.ip = addr;
196045679Sbostic     printf("%d.%d.%d.%d", imp_addr.imp.s_net, imp_addr.imp.s_host,
196145679Sbostic                 imp_addr.imp.s_lh, imp_addr.imp.s_impno);
196245679Sbostic #else
196345679Sbostic     printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
196445679Sbostic #endif
196545679Sbostic   }
196645679Sbostic 
196745679Sbostic /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
196845679Sbostic /*%%                            PRT_BYTES()                            %%*/
196945679Sbostic /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
197045679Sbostic /*                                                                       */
197145679Sbostic /*  Purpose:                                                             */
197245679Sbostic /*                                                                       */
197345679Sbostic /*	This routine is used to print a string of bytes in hex.		 */
197445679Sbostic /*	Note that this routine is for debugging purposes (ifdef          */
197545679Sbostic /*	ACPDEBUG).                                                       */
197645679Sbostic /*									 */
197745679Sbostic /*  Call:  		prt_bytes(bp, cnt)                               */
197845679Sbostic /*  Argument:      	bp:  pointer to the string                       */
197945679Sbostic /*                 	cnt: number of bytes                             */
198045679Sbostic /*  Returns:  		nothing                                          */
198145679Sbostic /*  Called by:  	acp_data()                                       */
198245679Sbostic /*              	acp_supr()                                       */
198345679Sbostic /*              	supr_msg()                                       */
198445679Sbostic /*  Calls to:   	printf()                                         */
198545679Sbostic /*									 */
198645679Sbostic /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
198745679Sbostic 
prt_bytes(bp,cnt)198845679Sbostic static void prt_bytes(bp, cnt)
198945679Sbostic u_char *bp;
199045679Sbostic int cnt;
199145679Sbostic   {
199245679Sbostic     while(cnt--)
199345679Sbostic       {
199445679Sbostic 	printf(" %x", *bp++ & 0xff);
199545679Sbostic       }
199645679Sbostic   }
199745679Sbostic 
199845679Sbostic #endif ACPDEBUG
199945679Sbostic 
200045679Sbostic #endif NACP
2001