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