1*45682Sbostic /*- 2*45682Sbostic * @(#)if_acp.c 7.2 (Berkeley) 12/02/90 3*45682Sbostic */ 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 11645679Sbostic #include "../machine/pte.h" 11745679Sbostic 11845679Sbostic #include "../h/param.h" 11945679Sbostic #include "../h/systm.h" 12045679Sbostic #include "../h/mbuf.h" 12145679Sbostic #include "../h/buf.h" 12245679Sbostic #include "../h/protosw.h" 12345679Sbostic #include "../h/socket.h" 12445679Sbostic #include "../h/vmmac.h" 12545679Sbostic #include "../h/errno.h" 12645679Sbostic #include "../h/time.h" 12745679Sbostic #include "../h/kernel.h" 12845679Sbostic #include "../h/ioctl.h" 12945679Sbostic 13045679Sbostic #include "../net/if.h" 13145679Sbostic #include "../net/netisr.h" 13245679Sbostic #include "../net/route.h" 13345679Sbostic #include "../netinet/in.h" 13445679Sbostic #include "../netinet/in_systm.h" 13545679Sbostic #ifndef FOURTWO 13645679Sbostic # include "../netinet/in_var.h" 13745679Sbostic #endif 13845679Sbostic #include "../netinet/ip.h" 13945679Sbostic #include "../netinet/ip_var.h" 14045679Sbostic 14145679Sbostic #include "../vax/cpu.h" 14245679Sbostic #include "../vax/mtpr.h" 14345679Sbostic #include "../vaxif/if_acpreg.h" 14445679Sbostic #include "../vaxif/if_acpvar.h" 14545679Sbostic #include "../vaxif/if_uba.h" 14645679Sbostic #include "../vaxuba/ubareg.h" 14745679Sbostic #include "../vaxuba/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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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