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