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